Audacity 3.2.0
WaveformView.cpp
Go to the documentation of this file.
1/**********************************************************************
2
3Audacity: A Digital Audio Editor
4
5WaveformView.cpp
6
7Paul Licameli split from WaveChannelView.cpp
8
9**********************************************************************/
10
11
12#include "WaveformView.h"
13
14#include "WaveformAppearance.h"
15#include "ClipParameters.h"
16#include "WaveChannelView.h"
18#include "WaveformCache.h"
20
21#include "SampleHandle.h"
22#include "../../../ui/EnvelopeHandle.h"
23#include "../../../ui/TimeShiftHandle.h"
24#include "AColor.h"
25#include "Envelope.h"
26#include "../../../../EnvelopeEditor.h"
27#include "PendingTracks.h"
28#include "../../../../ProjectSettings.h"
29#include "SelectedRegion.h"
30#include "SyncLock.h"
31#include "../../../../TrackArt.h"
32#include "../../../../TrackArtist.h"
33#include "../../../../TrackPanelDrawingContext.h"
34#include "../../../../TrackPanelMouseEvent.h"
35#include "ViewInfo.h"
37#include "WaveClip.h"
38#include "WaveTrack.h"
39#include "WaveTrackUtilities.h"
40#include "../../../../WaveTrackLocation.h"
41#include "../../../../prefs/WaveformSettings.h"
42
43#include "FrameStatistics.h"
44
45#include <wx/graphics.h>
46#include <wx/dc.h>
47
50 { wxT("Waveform"), XXO("Wa&veform") }
51};
52
54
56
57std::vector<UIHandlePtr> WaveformView::DetailedHitTest(
58 const TrackPanelMouseState &st,
59 const AudacityProject *pProject, int currentTool, bool bMultiTool )
60{
61 auto &view = *this;
62 const auto pChannel = view.FindChannel<WaveChannel>();
63
65 st, pProject, currentTool, bMultiTool, pChannel);
66 auto &results = pair.second;
67
68 if (!pair.first) {
69 UIHandlePtr result;
70
71 if (bMultiTool) {
72 // Conditional hit tests
73 // If Tools toolbar were eliminated, we would keep these
74 // The priority of these, in case more than one might apply at one
75 // point, seems arbitrary
76 if (nullptr != (result = EnvelopeHandle::WaveChannelHitTest(
77 view.mEnvelopeHandle, st.state, st.rect,
78 pProject, pChannel)))
79 results.push_back(result);
80 if (nullptr != (result = TimeShiftHandle::HitTest(
81 view.mTimeShiftHandle, st.state, st.rect,
82 pChannel->GetTrack().SharedPointer())))
83 // This is the hit test on the "grips" drawn left and
84 // right in Multi only
85 results.push_back(result);
86 if (nullptr != (result = SampleHandle::HitTest(
87 view.mSampleHandle, st.state, st.rect,
88 pProject, pChannel)))
89 results.push_back(result);
90 }
91 else {
92 switch ( currentTool ) {
93 // Unconditional hits appropriate to the tool
94 // If tools toolbar were eliminated, we would eliminate these
96 auto &viewInfo = ViewInfo::Get(*pProject);
97 auto time =
98 viewInfo.PositionToTime(st.state.m_x, st.rect.GetX());
99 const auto envelope =
102 view.mEnvelopeHandle, envelope,
103 std::dynamic_pointer_cast<const Channel>(pChannel),
104 false);
105 break;
106 }
109 view.mSampleHandle, st.state, pChannel);
110 break;
111 default:
112 result = {};
113 break;
114 }
115 if (result)
116 results.push_back(result);
117 }
118 }
119
120 return std::move( results );
121}
122
123void WaveformView::DoSetMinimized( bool minimized )
124{
125 auto wt = FindWaveChannel();
126
127 bool bHalfWave;
128 gPrefs->Read(wxT("/GUI/CollapseToHalfWave"), &bHalfWave, false);
129 if (wt && bHalfWave) {
130 auto &cache = WaveformScale::Get(*wt);
131 if (minimized)
132 // Zoom to show fractionally more than the top half of the wave.
133 cache.SetDisplayBounds( -0.01f, 1.0f );
134 else
135 // Zoom out full
136 cache.SetDisplayBounds( -1.0f, 1.0f );
137 }
138
140}
141
142auto WaveformView::SubViewType() const -> const Type &
143{
144 return sType;
145}
146
147std::shared_ptr<ChannelVRulerControls> WaveformView::DoGetVRulerControls()
148{
149 return std::make_shared<WaveformVRulerControls>(shared_from_this());
150}
151
152namespace
153{
154
156 int leftOffset, const wxRect &rect,
157 const double env[],
158 float zoomMin, float zoomMax,
159 int zeroLevelYCoordinate,
160 bool dB, float dBRange,
161 double t0, double t1,
162 bool bIsSyncLockSelected,
163 bool highlightEnvelope)
164{
165 auto &dc = context.dc;
166 const auto artist = TrackArtist::Get( context );
167 const auto &zoomInfo = *artist->pZoomInfo;
168
169 // Visually (one vertical slice of the waveform background, on its side;
170 // the "*" is the actual waveform background we're drawing
171 //
172 //1.0 0.0 -1.0
173 // |--------------------------------|--------------------------------|
174 // *************** ***************
175 // | | | |
176 // maxtop maxbot mintop minbot
177
178 int h = rect.height;
179 int halfHeight = wxMax(h / 2, 1);
180 int maxtop, lmaxtop = 0;
181 int mintop, lmintop = 0;
182 int maxbot, lmaxbot = 0;
183 int minbot, lminbot = 0;
184 bool sel, lsel = false;
185 int xx, lx = 0;
186 int l, w;
187
188 const auto &blankBrush = artist->blankBrush;
189 const auto &selectedBrush = artist->selectedBrush;
190 const auto &unselectedBrush = artist->unselectedBrush;
191
192 dc.SetPen(*wxTRANSPARENT_PEN);
193 dc.SetBrush(blankBrush);
194 dc.DrawRectangle(rect);
195
196 // Bug 2389 - always draw at least one pixel of selection.
197 int selectedX = zoomInfo.TimeToPosition(t0, -leftOffset);
198
199 double time = zoomInfo.PositionToTime(0, -leftOffset), nextTime;
200 for (xx = 0; xx < rect.width; ++xx, time = nextTime) {
201 nextTime = zoomInfo.PositionToTime(xx + 1, -leftOffset);
202 // First we compute the truncated shape of the waveform background.
203 // If drawEnvelope is true, then we compute the lower border of the
204 // envelope.
205
206 maxtop = GetWaveYPos(env[xx], zoomMin, zoomMax,
207 h, dB, true, dBRange, true);
208 maxbot = GetWaveYPos(env[xx], zoomMin, zoomMax,
209 h, dB, false, dBRange, true);
210
211 mintop = GetWaveYPos(-env[xx], zoomMin, zoomMax,
212 h, dB, false, dBRange, true);
213 minbot = GetWaveYPos(-env[xx], zoomMin, zoomMax,
214 h, dB, true, dBRange, true);
215
216 // Make sure it's odd so that a that max and min mirror each other
217 mintop +=1;
218 minbot +=1;
219
220 const auto drawEnvelope = artist->drawEnvelope;
221 if (!drawEnvelope || maxbot > mintop) {
222 maxbot = halfHeight;
223 mintop = halfHeight;
224 }
225
226 sel = (t0 <= time && nextTime < t1);
227 sel = sel || (xx == selectedX);
228 // We don't draw selection color for sync-lock selected tracks.
229 sel = sel && !bIsSyncLockSelected;
230
231 if (lmaxtop == maxtop &&
232 lmintop == mintop &&
233 lmaxbot == maxbot &&
234 lminbot == minbot &&
235 lsel == sel) {
236 continue;
237 }
238
239 dc.SetBrush(lsel ? selectedBrush : unselectedBrush);
240
241 l = rect.x + lx;
242 w = xx - lx;
243 if (lmaxbot < lmintop - 1) {
244 dc.DrawRectangle(l, rect.y + lmaxtop, w, lmaxbot - lmaxtop);
245 dc.DrawRectangle(l, rect.y + lmintop, w, lminbot - lmintop);
246 }
247 else {
248 dc.DrawRectangle(l, rect.y + lmaxtop, w, lminbot - lmaxtop);
249 }
250
251 if (highlightEnvelope && lmaxbot < lmintop - 1) {
252 dc.SetBrush( AColor::uglyBrush );
253 dc.DrawRectangle(l, rect.y + lmaxbot, w, lmintop - lmaxbot);
254 }
255
256 lmaxtop = maxtop;
257 lmintop = mintop;
258 lmaxbot = maxbot;
259 lminbot = minbot;
260 lsel = sel;
261 lx = xx;
262 }
263
264 dc.SetBrush(lsel ? selectedBrush : unselectedBrush);
265 l = rect.x + lx;
266 w = xx - lx;
267 if (lmaxbot < lmintop - 1) {
268 dc.DrawRectangle(l, rect.y + lmaxtop, w, lmaxbot - lmaxtop);
269 dc.DrawRectangle(l, rect.y + lmintop, w, lminbot - lmintop);
270 }
271 else {
272 dc.DrawRectangle(l, rect.y + lmaxtop, w, lminbot - lmaxtop);
273 }
274 if (highlightEnvelope && lmaxbot < lmintop - 1) {
275 dc.SetBrush( AColor::uglyBrush );
276 dc.DrawRectangle(l, rect.y + lmaxbot, w, lmintop - lmaxbot);
277 }
278
279 // If sync-lock selected, draw in linked graphics.
280 if (bIsSyncLockSelected && t0 < t1) {
281 const int begin = std::max(0, std::min(rect.width, (int)(zoomInfo.TimeToPosition(t0, -leftOffset))));
282 const int end = std::max(0, std::min(rect.width, (int)(zoomInfo.TimeToPosition(t1, -leftOffset))));
284 { rect.x + begin, rect.y, end - 1 - begin, rect.height } );
285 }
286
287 //OK, the display bounds are between min and max, which
288 //is spread across rect.height. Draw the line at the proper place.
289 if (zeroLevelYCoordinate >= rect.GetTop() &&
290 zeroLevelYCoordinate <= rect.GetBottom()) {
291 dc.SetPen(*wxBLACK_PEN);
292 AColor::Line(dc, rect.x, zeroLevelYCoordinate,
293 rect.x + rect.width - 1, zeroLevelYCoordinate);
294 }
295}
296
298 wxRect rect;
301 WavePortion(int x, int y, int w, int h, double zoom, bool i)
302 : rect(x, y, w, h), averageZoom(zoom), inFisheye(i)
303 {}
304};
305
307 (std::vector<WavePortion> &portions, const wxRect &rect, const ZoomInfo &zoomInfo,
308 const ClipParameters &params)
309{
310 // If there is no fisheye, then only one rectangle has nonzero width.
311 // If there is a fisheye, make rectangles for before and after
312 // (except when they are squeezed to zero width), and at least one for inside
313 // the fisheye.
314
315 const auto intervals = zoomInfo.FindIntervals(rect.width, rect.x);
316 ZoomInfo::Intervals::const_iterator it = intervals.begin(), end = intervals.end(), prev;
317 wxASSERT(it != end && it->position == rect.x);
318 const int rightmost = rect.x + rect.width;
319 for (int left = rect.x; left < rightmost;) {
320 while (it != end && it->position <= left)
321 prev = it++;
322 if (it == end)
323 break;
324 const int right = std::max(left, (int)(it->position));
325 const int width = right - left;
326 if (width > 0)
327 portions.push_back(
328 WavePortion(left, rect.y, width, rect.height,
329 prev->averageZoom, prev->inFisheye)
330 );
331 left = right;
332 }
333}
334
336 TrackPanelDrawingContext &context, const wxRect & rect, const double env[],
337 float zoomMin, float zoomMax,
338 bool dB, float dBRange,
339 const float *min, const float *max, const float *rms,
340 bool muted)
341{
342 auto &dc = context.dc;
343
344 // Display a line representing the
345 // min and max of the samples in this region
346 int lasth1 = std::numeric_limits<int>::max();
347 int lasth2 = std::numeric_limits<int>::min();
348 int h1;
349 int h2;
350 ArrayOf<int> r1{ size_t(rect.width) };
351 ArrayOf<int> r2{ size_t(rect.width) };
352 ArrayOf<int> clipped;
353 int clipcnt = 0;
354
355 const auto artist = TrackArtist::Get( context );
356 const auto bShowClipping = artist->mShowClipping;
357 if (bShowClipping) {
358 clipped.reinit( size_t(rect.width) );
359 }
360
361 long pixAnimOffset = (long)fabs((double)(wxDateTime::Now().GetTicks() * -10)) +
362 wxDateTime::Now().GetMillisecond() / 100; //10 pixels a second
363
364 const auto ms = wxDateTime::Now().GetMillisecond();
365 const auto ticks = (long)fabs((double)(wxDateTime::Now().GetTicks() * -10));
366
367 const auto &muteSamplePen = artist->muteSamplePen;
368 const auto &samplePen = artist->samplePen;
369
370 dc.SetPen(muted ? muteSamplePen : samplePen);
371 for (int x0 = 0; x0 < rect.width; ++x0) {
372 int xx = rect.x + x0;
373 double v;
374 v = min[x0] * env[x0];
375 if (clipped && bShowClipping && (v <= -MAX_AUDIO))
376 {
377 if (clipcnt == 0 || clipped[clipcnt - 1] != xx) {
378 clipped[clipcnt++] = xx;
379 }
380 }
381 h1 = GetWaveYPos(v, zoomMin, zoomMax,
382 rect.height, dB, true, dBRange, true);
383
384 v = max[x0] * env[x0];
385 if (clipped && bShowClipping && (v >= MAX_AUDIO))
386 {
387 if (clipcnt == 0 || clipped[clipcnt - 1] != xx) {
388 clipped[clipcnt++] = xx;
389 }
390 }
391 h2 = GetWaveYPos(v, zoomMin, zoomMax,
392 rect.height, dB, true, dBRange, true);
393
394 // JKC: This adjustment to h1 and h2 ensures that the drawn
395 // waveform is continuous.
396 if (x0 > 0) {
397 if (h1 < lasth2) {
398 h1 = lasth2 - 1;
399 }
400 if (h2 > lasth1) {
401 h2 = lasth1 + 1;
402 }
403 }
404 lasth1 = h1;
405 lasth2 = h2;
406
407 r1[x0] = GetWaveYPos(-rms[x0] * env[x0], zoomMin, zoomMax,
408 rect.height, dB, true, dBRange, true);
409 r2[x0] = GetWaveYPos(rms[x0] * env[x0], zoomMin, zoomMax,
410 rect.height, dB, true, dBRange, true);
411 // Make sure the rms isn't larger than the waveform min/max
412 if (r1[x0] > h1 - 1) {
413 r1[x0] = h1 - 1;
414 }
415 if (r2[x0] < h2 + 1) {
416 r2[x0] = h2 + 1;
417 }
418 if (r2[x0] > r1[x0]) {
419 r2[x0] = r1[x0];
420 }
421
422 AColor::Line(dc, xx, rect.y + h2, xx, rect.y + h1);
423 }
424
425 // Stroke rms over the min-max
426 const auto &muteRmsPen = artist->muteRmsPen;
427 const auto &rmsPen = artist->rmsPen;
428
429 dc.SetPen(muted ? muteRmsPen : rmsPen);
430 for (int x0 = 0; x0 < rect.width; ++x0) {
431 int xx = rect.x + x0;
432 if (r1[x0] != r2[x0]) {
433 AColor::Line(dc, xx, rect.y + r2[x0], xx, rect.y + r1[x0]);
434 }
435 }
436
437 // Draw the clipping lines
438 if (clipcnt) {
439 const auto &muteClippedPen = artist->muteClippedPen;
440 const auto &clippedPen = artist->clippedPen;
441
442 dc.SetPen(muted ? muteClippedPen : clippedPen);
443 while (--clipcnt >= 0) {
444 int xx = clipped[clipcnt];
445 AColor::Line(dc, xx, rect.y, xx, rect.y + rect.height);
446 }
447 }
448}
449
451 int leftOffset, const wxRect &rect,
452 float zoomMin, float zoomMax,
453 bool dB, float dBRange,
454 const WaveChannelInterval &clip,
455 bool showPoints, bool muted,
456 bool highlight)
457{
458 const Envelope &envelope = clip.GetEnvelope();
459 auto &dc = context.dc;
460 const auto artist = TrackArtist::Get(context);
461 const auto &zoomInfo = *artist->pZoomInfo;
462
463 const double toffset = clip.GetPlayStartTime();
464 const double rate = clip.GetRate() / clip.GetStretchRatio();
465 const double t0 = std::max(0.0, zoomInfo.PositionToTime(0, -leftOffset) - toffset);
466 const auto s0 = sampleCount(floor(t0 * rate));
467 const auto snSamples = clip.GetVisibleSampleCount();
468 if (s0 > snSamples)
469 return;
470
471 const double t1 = zoomInfo.PositionToTime(rect.width - 1, -leftOffset) - toffset;
472 const auto s1 = sampleCount(ceil(t1 * rate));
473
474 // Assume size_t will not overflow, else we wouldn't be here drawing the
475 // few individual samples
476 auto slen = std::min(snSamples - s0, s1 - s0 + 1).as_size_t();
477
478 if (slen <= 0)
479 return;
480
481 Floats buffer{ size_t(slen) };
482 clip.GetSamples((samplePtr)buffer.get(), floatSample, s0, slen,
483 // Suppress exceptions in this drawing operation:
484 false);
485
486 ArrayOf<int> xpos{ size_t(slen) };
487 ArrayOf<int> ypos{ size_t(slen) };
488 ArrayOf<int> clipped;
489 int clipcnt = 0;
490
491 const auto bShowClipping = artist->mShowClipping;
492 if (bShowClipping)
493 clipped.reinit( size_t(slen) );
494
495 const auto &muteSamplePen = artist->muteSamplePen;
496 const auto &samplePen = artist->samplePen;
497 auto &pen = highlight ? AColor::uglyPen : muted ? muteSamplePen : samplePen;
498 dc.SetPen( pen );
499
500 for (decltype(slen) s = 0; s < slen; s++) {
501 const double time = toffset + (s + s0).as_double() / rate;
502 const int xx = // An offset into the rectangle rect
503 std::max(-10000, std::min(10000,
504 (int)(zoomInfo.TimeToPosition(time, -leftOffset))));
505 xpos[s] = xx;
506
507 // Calculate sample as it would be rendered, so quantize time
508 double value = envelope.GetValue(time, 1.0 / clip.GetRate());
509 const double tt = buffer[s] * value;
510
511 if (clipped && bShowClipping && ((tt <= -MAX_AUDIO) || (tt >= MAX_AUDIO)))
512 clipped[clipcnt++] = xx;
513 ypos[s] =
514 std::max(-1,
515 std::min(rect.height,
516 GetWaveYPos(tt, zoomMin, zoomMax,
517 rect.height, dB, true, dBRange, false)));
518 }
519
520
521 if (showPoints) {
522 // Draw points where spacing is enough
523 const auto bigPoints = artist->bigPoints;
524 const int tickSize = bigPoints ? 4 : 3;// Bigger ellipses when draggable.
525 wxRect pr;
526 pr.width = tickSize;
527 pr.height = tickSize;
528 //different colour when draggable.
529 const auto &dragsampleBrush = artist->dragsampleBrush;
530 const auto &sampleBrush = artist->sampleBrush;
531 auto &brush = highlight
533 : bigPoints ? dragsampleBrush : sampleBrush;
534 dc.SetBrush( brush );
535 for (decltype(slen) s = 0; s < slen; s++) {
536 if (ypos[s] >= 0 && ypos[s] < rect.height) {
537 pr.x = rect.x + xpos[s] - tickSize/2;
538 pr.y = rect.y + ypos[s] - tickSize/2;
539 dc.DrawEllipse(pr);
540 }
541 }
542 }
543
544 const auto sampleDisplay = artist->mSampleDisplay;
545 if (showPoints &&
546 (sampleDisplay == (int) WaveChannelViewConstants::StemPlot)
547 ){
548 // Draw vertical lines
549 int yZero = GetWaveYPos(0.0, zoomMin, zoomMax, rect.height, dB, true, dBRange, false);
550 yZero = rect.y + std::max(-1, std::min(rect.height, yZero));
551 for (decltype(slen) s = 0; s < slen; s++) {
552 AColor::Line(dc,
553 rect.x + xpos[s], rect.y + ypos[s],
554 rect.x + xpos[s], yZero);
555 }
556 }
557 else {
558 // Connect samples with straight lines
559 for (decltype(slen) s = 0; s < slen - 1; s++) {
560 AColor::Line(dc,
561 rect.x + xpos[s], rect.y + ypos[s],
562 rect.x + xpos[s + 1], rect.y + ypos[s + 1]);
563 }
564 }
565
566 // Draw clipping
567 if (clipcnt) {
568 const auto &muteClippedPen = artist->muteClippedPen;
569 const auto &clippedPen = artist->clippedPen;
570 dc.SetPen(muted ? muteClippedPen : clippedPen);
571 while (--clipcnt >= 0) {
572 auto s = clipped[clipcnt];
573 AColor::Line(dc, rect.x + s, rect.y, rect.x + s, rect.y + rect.height);
574 }
575 }
576}
577
580 const wxRect &rect, int x0, int y0, int cy, bool top )
581{
582 auto &dc = context.dc;
583
584 int xx = rect.x + x0;
585 int yy = rect.y + cy;
586
587 if (y0 < 0) {
588 if (x0 % 4 != 3) {
589 AColor::Line(dc, xx, yy, xx, yy + 3);
590 }
591 }
592 else if (y0 > rect.height) {
593 if (x0 % 4 != 3) {
594 AColor::Line(dc, xx, yy - 3, xx, yy);
595 }
596 }
597 else {
598 if (top) {
599 AColor::Line(dc, xx, yy, xx, yy + 3);
600 }
601 else {
602 AColor::Line(dc, xx, yy - 3, xx, yy);
603 }
604 }
605}
606
608 const wxRect &rect, const double env[],
609 float zoomMin, float zoomMax,
610 bool dB, float dBRange, bool highlight)
611{
612 auto &dc = context.dc;
613
614 int h = rect.height;
615
616 auto &pen = highlight ? AColor::uglyPen : AColor::envelopePen;
617 dc.SetPen( pen );
618
619 for (int x0 = 0; x0 < rect.width; ++x0) {
620 int cenvTop = GetWaveYPos(env[x0], zoomMin, zoomMax,
621 h, dB, true, dBRange, true);
622
623 int cenvBot = GetWaveYPos(-env[x0], zoomMin, zoomMax,
624 h, dB, true, dBRange, true);
625
626 int envTop = GetWaveYPos(env[x0], zoomMin, zoomMax,
627 h, dB, true, dBRange, false);
628
629 int envBot = GetWaveYPos(-env[x0], zoomMin, zoomMax,
630 h, dB, true, dBRange, false);
631
632 // Make the collision at zero actually look solid
633 if (cenvBot - cenvTop < 9) {
634 int value = (int)((zoomMax / (zoomMax - zoomMin)) * h);
635 cenvTop = value - 4;
636 cenvBot = value + 4;
637 }
638
639 DrawEnvLine( context, rect, x0, envTop, cenvTop, true );
640 DrawEnvLine( context, rect, x0, envBot, cenvBot, false );
641 }
642}
643
644// Headers needed only for experimental drawing below
645//#include "tracks/playabletrack/wavetrack/ui/SampleHandle.h"
646//#include "tracks/ui/EnvelopeHandle.h"
648 const WaveChannel &channel, const WaveChannelInterval &clip,
649 const wxRect &rect, bool dB, bool muted, bool selected)
650{
651 const Envelope &envelope = clip.GetEnvelope();
652 auto &dc = context.dc;
653 const auto artist = TrackArtist::Get(context);
654 const auto &selectedRegion = *artist->pSelectedRegion;
655 const auto &zoomInfo = *artist->pZoomInfo;
656
658
659 bool highlightEnvelope = false;
660#ifdef EXPERIMENTAL_TRACK_PANEL_HIGHLIGHTING
661 auto target = dynamic_cast<EnvelopeHandle*>(context.target.get());
662 highlightEnvelope = target && target->GetEnvelope() == &envelope;
663#endif
664
665 //If clip is "too small" draw a placeholder instead of
666 //attempting to fit the contents into a few pixels
667 if (!WaveChannelView::ClipDetailsVisible(clip, zoomInfo, rect))
668 {
669 auto clipRect = ClipParameters::GetClipRect(clip, zoomInfo, rect);
670 TrackArt::DrawClipFolded(dc, clipRect);
671 return;
672 }
673
674 const ClipParameters params { clip, rect, zoomInfo };
675 const wxRect &hiddenMid = params.hiddenMid;
676 // The "hiddenMid" rect contains the part of the display actually
677 // containing the waveform, as it appears without the fisheye. If it's empty, we're done.
678 if (hiddenMid.width <= 0) {
679 return;
680 }
681
682 const double &t0 = params.t0;
683 const double playStartTime = clip.GetPlayStartTime();
684 const double &trackRectT0 = params.trackRectT0;
685 const double &averagePixelsPerSecond = params.averagePixelsPerSecond;
686 const double sampleRate = clip.GetRate();
687 const double stretchRatio = clip.GetStretchRatio();
688 double leftOffset = params.leftOffset;
689 const wxRect &mid = params.mid;
690
691 auto &settings = WaveformSettings::Get(channel);
692 const float dBRange = settings.dBRange;
693
694 dc.SetPen(*wxTRANSPARENT_PEN);
695 int iColorIndex = WaveColorAttachment::Get(clip).GetColorIndex();
696 artist->SetColours( iColorIndex );
697
698 // The bounds (controlled by vertical zooming; -1.0...1.0
699 // by default)
700 float zoomMin, zoomMax;
701 auto &cache = WaveformScale::Get(channel);
702 cache.GetDisplayBounds(zoomMin, zoomMax);
703
704 std::vector<double> vEnv(mid.width);
705 double *const env = &vEnv[0];
706 CommonChannelView::GetEnvelopeValues(envelope, playStartTime,
707
708 // PRL: change back to make envelope evaluate only at sample times
709 // and then interpolate the display
710 0, // 1.0 / sampleRate,
711
712 env, mid.width, leftOffset, zoomInfo);
713
714 // Draw the background of the track, outlining the shape of
715 // the envelope and using a colored pen for the selected
716 // part of the waveform
717 {
718 double tt0, tt1;
719 const auto &track = channel.GetTrack();
721 tt0 = track.SnapToSample(selectedRegion.t0());
722 tt1 = track.SnapToSample(selectedRegion.t1());
723 }
724 else
725 tt0 = tt1 = 0.0;
726 DrawWaveformBackground(context, leftOffset, mid,
727 env,
728 zoomMin, zoomMax,
729 cache.ZeroLevelYCoordinate(mid),
730 dB, dBRange,
731 tt0, tt1,
732 !track.GetSelected(), highlightEnvelope);
733 }
734
735 WaveDisplay display(hiddenMid.width);
736
737 // For each portion separately, we will decide to draw
738 // it as min/max/rms or as individual samples.
739 std::vector<WavePortion> portions;
740 FindWavePortions(portions, rect, zoomInfo, params);
741 const unsigned nPortions = portions.size();
742
743 // Require at least 1/2 pixel per sample for drawing individual samples.
744 const double threshold1 = 0.5 * sampleRate / stretchRatio;
745 // Require at least 3 pixels per sample for drawing the draggable points.
746 const double threshold2 = 3 * sampleRate / stretchRatio;
747
748 auto &clipCache = WaveClipWaveformCache::Get(clip);
749
750 {
751 bool showIndividualSamples = false;
752 for (unsigned ii = 0; !showIndividualSamples && ii < nPortions; ++ii) {
753 const WavePortion &portion = portions[ii];
754 showIndividualSamples =
755 !portion.inFisheye && portion.averageZoom > threshold1;
756 }
757
758 if (!showIndividualSamples) {
759 // The WaveClip class handles the details of computing the shape
760 // of the waveform. The only way GetWaveDisplay will fail is if
761 // there's a serious error, like some of the waveform data can't
762 // be loaded. So if the function returns false, we can just exit.
763
764 // Note that we compute the full width display even if there is a
765 // fisheye hiding part of it, because of the caching. If the
766 // fisheye moves over the background, there is then less to do when
767 // redrawing.
768
769 if (!clipCache.GetWaveDisplay(clip,
770 display, t0, averagePixelsPerSecond))
771 return;
772 }
773 }
774
775 // TODO Add a comment to say what this loop does.
776 // Possibly make it into a subroutine.
777 for (unsigned ii = 0; ii < nPortions; ++ii) {
778 WavePortion &portion = portions[ii];
779 const bool showIndividualSamples = portion.averageZoom > threshold1;
780 const bool showPoints = portion.averageZoom > threshold2;
781 wxRect& rectPortion = portion.rect;
782 rectPortion.Intersect(mid);
783 wxASSERT(rectPortion.width >= 0);
784
785 float *useMin = 0, *useMax = 0, *useRms = 0;
786 WaveDisplay fisheyeDisplay(rectPortion.width);
787 int skipped = 0, skippedLeft = 0, skippedRight = 0;
788 if (portion.inFisheye) {
789 if (!showIndividualSamples) {
790 fisheyeDisplay.Allocate();
791 const auto numSamples = clip.GetVisibleSampleCount();
792 // Get wave display data for different magnification
793 int jj = 0;
794 for (; jj < rectPortion.width; ++jj) {
795 const double time =
796 zoomInfo.PositionToTime(jj, -leftOffset) - playStartTime;
797 const auto sample = clip.TimeToSamples(time);
798 if (sample < 0) {
799 ++rectPortion.x;
800 ++skippedLeft;
801 continue;
802 }
803 if (sample >= numSamples)
804 break;
805 fisheyeDisplay.where[jj - skippedLeft] = sample;
806 }
807
808 skippedRight = rectPortion.width - jj;
809 skipped = skippedRight + skippedLeft;
810 rectPortion.width -= skipped;
811
812 // where needs a sentinel
813 if (jj > 0)
814 fisheyeDisplay.where[jj - skippedLeft] =
815 1 + fisheyeDisplay.where[jj - skippedLeft - 1];
816 fisheyeDisplay.width -= skipped;
817 // Get a wave display for the fisheye, uncached.
818 if (rectPortion.width > 0)
819 if (!clipCache.GetWaveDisplay(clip,
820 fisheyeDisplay, t0, -1.0)) // ignored
821 continue; // serious error. just don't draw??
822 useMin = fisheyeDisplay.min;
823 useMax = fisheyeDisplay.max;
824 useRms = fisheyeDisplay.rms;
825 }
826 }
827 else {
828 const int pos = leftOffset - params.hiddenLeftOffset;
829 useMin = display.min + pos;
830 useMax = display.max + pos;
831 useRms = display.rms + pos;
832 }
833
834 leftOffset += skippedLeft;
835
836 if (rectPortion.width > 0) {
837 if (!showIndividualSamples) {
838 std::vector<double> vEnv2(rectPortion.width);
839 double *const env2 = &vEnv2[0];
840 CommonChannelView::GetEnvelopeValues(envelope, playStartTime,
841
842 // PRL: change back to make envelope evaluate only at sample
843 // times and then interpolate the display
844 0, // 1.0 / sampleRate,
845
846 env2, rectPortion.width, leftOffset, zoomInfo);
847
848 DrawMinMaxRMS(context, rectPortion, env2,
849 zoomMin, zoomMax,
850 dB, dBRange,
851 useMin, useMax, useRms, muted);
852 }
853 else {
854 bool highlight = false;
855#ifdef EXPERIMENTAL_TRACK_PANEL_HIGHLIGHTING
856 auto target = dynamic_cast<SampleHandle*>(context.target.get());
857 highlight = target && target->FindTrack().get() ==
858 &static_cast<const Track&>(channel.GetChannelGroup());
859#endif
861 context, leftOffset, rectPortion, zoomMin, zoomMax,
862 dB, dBRange, clip, showPoints, muted, highlight);
863 }
864 }
865
866 leftOffset += rectPortion.width + skippedRight;
867 }
868
869 const auto drawEnvelope = artist->drawEnvelope;
870 if (drawEnvelope) {
872 context, mid, env, zoomMin, zoomMax, dB, dBRange, highlightEnvelope);
874 context, mid, dB, dBRange, zoomMin, zoomMax, true, rect.x - mid.x);
875 }
876
877 // Draw arrows on the left side if the track extends to the left of the
878 // beginning of time. :)
879 if (trackRectT0 == 0.0 && playStartTime < 0.0)
880 {
882 }
883 {
884 auto clipRect = ClipParameters::GetClipRect(clip, zoomInfo, rect);
885 TrackArt::DrawClipEdges(dc, clipRect, selected);
886 }
887}
888
890 const wxRect & rect,
891 bool rightwards, bool highlight )
892{
893 auto &dc = context.dc;
894
895 const int border = 3; // 3 pixels all round.
896 const int width = 6; // width of the drag box.
897 const int taper = 6; // how much the box tapers by.
898 const int barSpacing = 4; // how far apart the bars are.
899 const int barWidth = 3;
900 const int xFlat = 3;
901
902 //Enough space to draw in?
903 if (rect.height <= ((taper+border + barSpacing) * 2)) {
904 return;
905 }
906 if (rect.width <= (width * 2 + border * 3)) {
907 return;
908 }
909
910 // The draggable box is tapered towards the direction you drag it.
911 int leftTaper = rightwards ? 0 : 6;
912 int rightTaper = rightwards ? 6 : 0;
913
914 int xLeft = rightwards ? (rect.x + border - 2)
915 : (rect.x + rect.width + 1 - (border + width));
916 int yTop = rect.y + border;
917 int yBot = rect.y + rect.height - border - 1;
918
919 AColor::Light(&dc, false, highlight);
920 AColor::Line(dc, xLeft, yBot - leftTaper, xLeft, yTop + leftTaper);
921 AColor::Line(dc, xLeft, yTop + leftTaper, xLeft + xFlat, yTop);
922 AColor::Line(dc, xLeft + xFlat, yTop, xLeft + width, yTop + rightTaper);
923
924 AColor::Dark(&dc, false, highlight);
925 AColor::Line(dc, xLeft + width, yTop + rightTaper, xLeft + width, yBot - rightTaper);
926 AColor::Line(dc, xLeft + width, yBot - rightTaper, xLeft + width-xFlat, yBot);
927 AColor::Line(dc, xLeft + width - xFlat, yBot, xLeft, yBot - leftTaper);
928
929 int firstBar = yTop + taper + taper / 2;
930 int nBars = (yBot - yTop - taper * 3) / barSpacing + 1;
931 xLeft += (width - barWidth + 1) / 2;
932 int yy;
933 int i;
934
935 AColor::Light(&dc, false, highlight);
936 for (i = 0;i < nBars; i++) {
937 yy = firstBar + barSpacing * i;
938 AColor::Line(dc, xLeft, yy, xLeft + barWidth, yy);
939 }
940 AColor::Dark(&dc, false, highlight);
941 for(i = 0;i < nBars; i++){
942 yy = firstBar + barSpacing * i + 1;
943 AColor::Line(dc, xLeft, yy, xLeft + barWidth, yy);
944 }
945}
946
947}
948
949// Header needed only for experimental drawing below
950//#include "tracks/ui/TimeShiftHandle.h"
952 const WaveChannel &channel,
953 const WaveTrack::Interval* selectedClip,
954 const wxRect& rect,
955 bool muted)
956{
957 auto &dc = context.dc;
958 const auto artist = TrackArtist::Get( context );
959
960 bool highlight = false;
961 bool gripHit = false;
962#ifdef EXPERIMENTAL_TRACK_PANEL_HIGHLIGHTING
963 auto target = dynamic_cast<TimeShiftHandle*>(context.target.get());
964 gripHit = target && target->IsGripHit();
965 highlight = target && target->FindTrack().get() ==
966 &static_cast<const Track &>(channel.GetChannelGroup());
967#endif
968
969 const bool dB = !WaveformSettings::Get(channel).isLinear();
970
971 const auto &blankSelectedBrush = artist->blankSelectedBrush;
972 const auto &blankBrush = artist->blankBrush;
974 context, rect, channel, blankSelectedBrush, blankBrush );
975
976 for (const auto &pInterval : channel.Intervals()) {
977 bool selected = selectedClip &&
978 selectedClip == &pInterval->GetClip();
979 DrawClipWaveform(context, channel, *pInterval, rect, dB, muted, selected);
980 }
981 DrawBoldBoundaries(context, channel, rect);
982
983 const auto drawSliders = artist->drawSliders;
984 if (drawSliders) {
985 DrawTimeSlider( context, rect, true, highlight && gripHit ); // directed right
986 DrawTimeSlider( context, rect, false, highlight && gripHit ); // directed left
987 }
988}
989
991 TrackPanelDrawingContext &context, const wxRect &rect, unsigned iPass )
992{
993 if ( iPass == TrackArtist::PassTracks ) {
994 const auto artist = TrackArtist::Get(context);
995 const auto &pendingTracks = *artist->pPendingTracks;
996 auto &dc = context.dc;
997
998 const auto pChannel = FindChannel();
999 if (!pChannel)
1000 return;
1001 const auto &wc = static_cast<const WaveChannel&>(
1002 pendingTracks.SubstitutePendingChangedChannel(*pChannel));
1003
1004 const auto hasSolo = artist->hasSolo;
1005 bool muted = (hasSolo || wc.GetTrack().GetMute()) &&
1006 !wc.GetTrack().GetSolo();
1007
1008#if defined(__WXMAC__)
1009 wxAntialiasMode aamode = dc.GetGraphicsContext()->GetAntialiasMode();
1010 dc.GetGraphicsContext()->SetAntialiasMode(wxANTIALIAS_NONE);
1011#endif
1012
1013 auto waveChannelView = GetWaveChannelView().lock();
1014 wxASSERT(waveChannelView.use_count());
1015
1016 auto selectedClip = waveChannelView->GetSelectedClip();
1017 DoDraw(context, wc, selectedClip.get(), rect, muted);
1018
1019#if defined(__WXMAC__)
1020 dc.GetGraphicsContext()->SetAntialiasMode(aamode);
1021#endif
1022 }
1023 WaveChannelSubView::Draw(context, rect, iPass);
1024}
1025
1027 [](WaveChannelView &view) {
1028 return std::make_shared<WaveformView>( view );
1029 }
1030};
1031
1032// The following attaches the wave color sub-menu to the wave track popup
1033// menu. It is appropriate only to waveform view and so is kept in this
1034// source file with the rest of the waveform view implementation.
1035
1036#include <mutex> // for std::call_once
1037#include "WaveTrackControls.h"
1038#include "../../../../widgets/PopupMenuTable.h"
1039#include "ProjectAudioIO.h"
1040#include "ProjectHistory.h"
1041#include "../../../../RefreshCode.h"
1042
1043//=============================================================================
1044// Table class for a sub-menu
1046{
1047 WaveColorMenuTable() : PopupMenuTable{ "WaveColor", XO("&Wave Color") } {}
1049
1050 static WaveColorMenuTable &Instance();
1051
1052 void InitUserData(void *pUserData) override;
1053
1055
1056 int IdOfWaveColor(int WaveColor);
1057 void OnWaveColorChange(wxCommandEvent & event);
1058
1060};
1061
1063{
1064 static WaveColorMenuTable instance;
1065 return instance;
1066}
1067
1069{
1070 mpData = static_cast<PlayableTrackControls::InitMenuData*>(pUserData);
1071}
1072
1073namespace {
1074using ValueFinder = std::function< int( WaveTrack& ) >;
1075
1077{
1078 return XXO("Instrument %i").Format( colorIndex+1 );
1079}
1080}
1081
1083 static const auto fn = []( PopupMenuHandler &handler, wxMenu &menu, int id ){
1084 auto &me = static_cast<WaveColorMenuTable&>( handler );
1085 auto pData = me.mpData;
1086 const auto &track = static_cast<WaveTrack&>(pData->track);
1087 auto &project = pData->project;
1088 bool unsafe = ProjectAudioIO::Get( project ).IsAudioActive();
1089
1090 menu.Check(id, id == me.IdOfWaveColor(
1092 menu.Enable( id, !unsafe );
1093 };
1094
1095 static std::once_flag flag;
1096 std::call_once( flag, [this]{
1097 auto &hostTable = GetWaveTrackMenuTable();
1098 OnInstrument1ID = hostTable.ReserveId();
1099 OnInstrument2ID = hostTable.ReserveId();
1100 OnInstrument3ID = hostTable.ReserveId();
1101 OnInstrument4ID = hostTable.ReserveId();
1102 } );
1103
1104 AppendRadioItem( "Instrument1", OnInstrument1ID,
1105 GetWaveColorStr(0), POPUP_MENU_FN( OnWaveColorChange ), fn );
1106 AppendRadioItem( "Instrument2", OnInstrument2ID,
1107 GetWaveColorStr(1), POPUP_MENU_FN( OnWaveColorChange ), fn );
1108 AppendRadioItem( "Instrument3", OnInstrument3ID,
1109 GetWaveColorStr(2), POPUP_MENU_FN( OnWaveColorChange ), fn );
1110 AppendRadioItem( "Instrument4", OnInstrument4ID,
1111 GetWaveColorStr(3), POPUP_MENU_FN( OnWaveColorChange ), fn );
1112
1114
1115
1116int WaveColorMenuTable::IdOfWaveColor(int WaveColor)
1117{ return OnInstrument1ID + WaveColor;}
1118
1121void WaveColorMenuTable::OnWaveColorChange(wxCommandEvent & event)
1122{
1123 int id = event.GetId();
1124 wxASSERT(id >= OnInstrument1ID && id <= OnInstrument4ID);
1125 auto &track = static_cast<WaveTrack&>(mpData->track);
1126
1127 int newWaveColor = id - OnInstrument1ID;
1128
1130
1131 WaveformAppearance::Get(track).SetColorIndex(newWaveColor);
1132
1134 .PushState(XO("Changed '%s' to %s")
1135 .Format(track.GetName(), GetWaveColorStr(newWaveColor)),
1136 XO("WaveColor Change"));
1137
1138 using namespace RefreshCode;
1140}
1141
1142namespace {
1145 { "SubViews/Extra" },
1146 std::make_unique<PopupMenuSection>( "WaveColor",
1147 // Conditionally add sub-menu for wave color, if showing waveform
1148 PopupMenuTable::Adapt<WaveTrackPopupMenuTable>(
1149 [](WaveTrackPopupMenuTable &table) {
1150 const auto pTrack = &table.FindWaveTrack();
1151 const auto &view = WaveChannelView::GetFirst(*pTrack);
1152 const auto displays = view.GetDisplays();
1153 bool hasWaveform = (displays.end() != std::find(
1154 displays.begin(), displays.end(),
1156 WaveChannelViewConstants::Waveform, {} }
1157 ) );
1158 return hasWaveform
1160 .Get(table.mpData))
1161 : nullptr;
1162 } ) )
1163};
1164}
wxT("CloseDown"))
std::shared_ptr< UIHandle > UIHandlePtr
Definition: CellularPanel.h:28
int min(int a, int b)
EffectDistortionSettings params
Definition: Distortion.cpp:77
XO("Cut/Copy/Paste")
XXO("&Cut/Copy/Paste Toolbar")
#define MAX_AUDIO
Definition: MemoryX.h:340
#define END_POPUP_MENU()
#define BEGIN_POPUP_MENU(HandlerClass)
#define POPUP_MENU_FN(memFn)
audacity::BasicSettings * gPrefs
Definition: Prefs.cpp:68
constexpr sampleFormat floatSample
Definition: SampleFormat.h:45
char * samplePtr
Definition: SampleFormat.h:57
const auto project
int GetWaveYPos(float value, float min, float max, int height, bool dB, bool outer, float dBr, bool clip)
Definition: TrackArt.cpp:66
static Settings & settings()
Definition: TrackInfo.cpp:69
WaveTrackPopupMenuTable & GetWaveTrackMenuTable()
static WaveChannelSubViewType::RegisteredType reg
static const auto fn
AppendRadioItem("Instrument1", OnInstrument1ID, GetWaveColorStr(0), POPUP_MENU_FN(OnWaveColorChange), fn)
static const WaveChannelSubViews::RegisteredFactory key
static WaveChannelSubView::Type sType
static std::once_flag flag
static void Line(wxDC &dc, wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2)
Definition: AColor.cpp:187
static wxBrush uglyBrush
Definition: AColor.h:142
static void Light(wxDC *dc, bool selected, bool highlight=false)
Definition: AColor.cpp:409
static wxPen uglyPen
Definition: AColor.h:141
static void Dark(wxDC *dc, bool selected, bool highlight=false)
Definition: AColor.cpp:435
static wxPen envelopePen
Definition: AColor.h:115
void reinit(Integral count, bool initialize=false)
Definition: MemoryX.h:58
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
Definition: Project.h:90
ChannelGroup & GetChannelGroup()
Channel object's lifetime is assumed to be nested in its Track's.
Definition: Channel.cpp:43
virtual void DoSetMinimized(bool isMinimized)
Client code makes static instance from a factory of attachments; passes it to Get or Find as a retrie...
Definition: ClientData.h:275
auto FindChannel() -> std::shared_ptr< Subtype >
May return null.
static void GetEnvelopeValues(const Envelope &env, double aligned_time, double sampleDur, double *buffer, int bufferLen, int leftOffset, const ZoomInfo &zoomInfo)
Get many envelope points for pixel columns at once, but don't assume uniform time per pixel.
static void DrawPoints(const Envelope &env, TrackPanelDrawingContext &context, const wxRect &r, bool dB, double dBRange, float zoomMin, float zoomMax, bool mirrored, int origin=0)
static UIHandlePtr WaveChannelHitTest(std::weak_ptr< EnvelopeHandle > &holder, const wxMouseState &state, const wxRect &rect, const AudacityProject *pProject, const std::shared_ptr< WaveChannel > &wt)
Envelope * GetEnvelope() const
static UIHandlePtr HitAnywhere(std::weak_ptr< EnvelopeHandle > &holder, Envelope *envelope, std::weak_ptr< const Channel > wChannel, bool timeTrack)
Piecewise linear or piecewise exponential function from double to double.
Definition: Envelope.h:72
double GetValue(double t, double sampleDur=0) const
Get envelope value at time t.
Definition: Envelope.cpp:838
Abstract base class used in importing a file.
@ WaveformView
Time required to draw a single clip.
static Stopwatch CreateStopwatch(SectionID section) noexcept
Create a Stopwatch for the section specified.
bool IsAudioActive() const
static ProjectAudioIO & Get(AudacityProject &project)
void PushState(const TranslatableString &desc, const TranslatableString &shortDesc)
static ProjectHistory & Get(AudacityProject &project)
static UIHandlePtr HitAnywhere(std::weak_ptr< SampleHandle > &holder, const wxMouseState &state, const std::shared_ptr< WaveChannel > &pChannel)
std::shared_ptr< const Track > FindTrack() const override
static UIHandlePtr HitTest(std::weak_ptr< SampleHandle > &holder, const wxMouseState &state, const wxRect &rect, const AudacityProject *pProject, const std::shared_ptr< WaveChannel > &pChannel)
static bool IsSelectedOrSyncLockSelected(const Track &track)
Definition: SyncLock.cpp:104
static UIHandlePtr HitTest(std::weak_ptr< TimeShiftHandle > &holder, const wxMouseState &state, const wxRect &rect, const std::shared_ptr< Track > &pTrack)
bool IsGripHit() const
static TrackArtist * Get(TrackPanelDrawingContext &)
Definition: TrackArtist.cpp:69
Abstract base class for an object holding data associated with points on a time axis.
Definition: Track.h:110
virtual void Draw(TrackPanelDrawingContext &context, const wxRect &rect, unsigned iPass)
Holds a msgid for the translation catalog; may also bind format arguments.
static ViewInfo & Get(AudacityProject &project)
Definition: ViewInfo.cpp:235
WaveTrack & GetTrack()
Definition: WaveTrack.h:840
IteratorRange< IntervalIterator< WaveClipChannel > > Intervals()
Definition: WaveTrack.cpp:745
std::shared_ptr< WaveChannel > FindWaveChannel()
static void DrawBoldBoundaries(TrackPanelDrawingContext &context, const WaveChannel &channel, const wxRect &rect)
std::pair< bool, std::vector< UIHandlePtr > > DoDetailedHitTest(const TrackPanelMouseState &state, const AudacityProject *pProject, int currentTool, bool bMultiTool, const std::shared_ptr< WaveChannel > &wt)
std::weak_ptr< WaveChannelView > GetWaveChannelView() const
static bool ClipDetailsVisible(const ClipTimes &clip, const ZoomInfo &zoomInfo, const wxRect &viewRect)
static WaveChannelView & GetFirst(WaveTrack &wt)
Get the view of the first channel.
sampleCount GetVisibleSampleCount() const override
Definition: WaveClip.cpp:188
Envelope & GetEnvelope()
Definition: WaveClip.cpp:64
int GetRate() const override
Definition: WaveClip.cpp:193
double GetPlayStartTime() const override
Definition: WaveClip.cpp:198
double GetStretchRatio() const override
Definition: WaveClip.cpp:218
sampleCount TimeToSamples(double time) const override
Definition: WaveClip.cpp:213
bool GetSamples(samplePtr buffer, sampleFormat format, sampleCount start, size_t len, bool mayThrow=true) const
Definition: WaveClip.cpp:115
This allows multiple clips to be a part of one WaveTrack.
Definition: WaveClip.h:238
float * rms
Definition: WaveformCache.h:26
sampleCount * where
Definition: WaveformCache.h:25
float * min
Definition: WaveformCache.h:26
float * max
Definition: WaveformCache.h:26
void Allocate()
Definition: WaveformCache.h:38
A Track that contains audio waveform data.
Definition: WaveTrack.h:203
bool GetSolo() const override
May vary asynchronously.
Definition: WaveTrack.cpp:2323
static WaveformAppearance & Get(WaveTrack &track)
void SetColorIndex(int colorIndex)
static WaveformScale & Get(const WaveTrack &track)
Mutative access to attachment even if the track argument is const.
bool isLinear() const
static WaveformSettings & Get(const WaveTrack &track)
void Draw(TrackPanelDrawingContext &context, const wxRect &rect, unsigned iPass) override
~WaveformView() override
std::shared_ptr< ChannelVRulerControls > DoGetVRulerControls() override
static void DoDraw(TrackPanelDrawingContext &context, const WaveChannel &channel, const WaveTrack::Interval *selectedClip, const wxRect &rect, bool muted)
void DoSetMinimized(bool minimized) override
const Type & SubViewType() const override
std::vector< UIHandlePtr > DetailedHitTest(const TrackPanelMouseState &state, const AudacityProject *pProject, int currentTool, bool bMultiTool) override
double SnapToSample(double t) const
Intervals FindIntervals(int64 width, int64 origin=0) const
Definition: ZoomInfo.cpp:99
virtual bool Read(const wxString &key, bool *value) const =0
Positions or offsets within audio files need a wide type.
Definition: SampleCount.h:19
Services * Get()
Fetch the global instance, or nullptr if none is yet installed.
Definition: BasicUI.cpp:196
Namespace containing an enum 'what to do on a refresh?'.
Definition: RefreshCode.h:16
std::unique_ptr< detail::IndirectItem< Item > > Indirect(const std::shared_ptr< Item > &ptr)
A convenience function.
Definition: Registry.h:175
AUDACITY_DLL_API void DrawSyncLockTiles(TrackPanelDrawingContext &context, const wxRect &rect)
Definition: TrackArt.cpp:365
AUDACITY_DLL_API void DrawClipFolded(wxDC &dc, const wxRect &rect)
Definition: TrackArt.cpp:346
AUDACITY_DLL_API void DrawClipEdges(wxDC &dc, const wxRect &clipRect, bool selected=false)
Definition: TrackArt.cpp:309
AUDACITY_DLL_API void DrawNegativeOffsetTrackArrows(TrackPanelDrawingContext &context, const wxRect &rect)
Definition: TrackArt.cpp:143
AUDACITY_DLL_API void DrawBackgroundWithSelection(TrackPanelDrawingContext &context, const wxRect &rect, const Channel &channel, const wxBrush &selBrush, const wxBrush &unselBrush, bool useSelection=true)
Definition: TrackArt.cpp:651
WAVE_TRACK_API Envelope * GetEnvelopeAtTime(WaveChannel &channel, double time)
void DrawClipWaveform(TrackPanelDrawingContext &context, const WaveChannel &channel, const WaveChannelInterval &clip, const wxRect &rect, bool dB, bool muted, bool selected)
std::function< int(WaveTrack &) > ValueFinder
const TranslatableString GetWaveColorStr(int colorIndex)
void DrawEnvLine(TrackPanelDrawingContext &context, const wxRect &rect, int x0, int y0, int cy, bool top)
void DrawIndividualSamples(TrackPanelDrawingContext &context, int leftOffset, const wxRect &rect, float zoomMin, float zoomMax, bool dB, float dBRange, const WaveChannelInterval &clip, bool showPoints, bool muted, bool highlight)
void DrawEnvelope(TrackPanelDrawingContext &context, const wxRect &rect, const double env[], float zoomMin, float zoomMax, bool dB, float dBRange, bool highlight)
void DrawTimeSlider(TrackPanelDrawingContext &context, const wxRect &rect, bool rightwards, bool highlight)
PopupMenuTable::AttachedItem sAttachment
void FindWavePortions(std::vector< WavePortion > &portions, const wxRect &rect, const ZoomInfo &zoomInfo, const ClipParameters &params)
void DrawMinMaxRMS(TrackPanelDrawingContext &context, const wxRect &rect, const double env[], float zoomMin, float zoomMax, bool dB, float dBRange, const float *min, const float *max, const float *rms, bool muted)
void DrawWaveformBackground(TrackPanelDrawingContext &context, int leftOffset, const wxRect &rect, const double env[], float zoomMin, float zoomMax, int zeroLevelYCoordinate, bool dB, float dBRange, double t0, double t1, bool bIsSyncLockSelected, bool highlightEnvelope)
const char * end(const char *str) noexcept
Definition: StringUtils.h:106
const char * begin(const char *str) noexcept
Definition: StringUtils.h:101
static wxRect GetClipRect(const ClipTimes &clip, const ZoomInfo &zoomInfo, const wxRect &viewRect, bool *outShowSamples=nullptr)
static WaveClipWaveformCache & Get(const WaveChannelInterval &clip)
static WaveColorAttachment & Get(WaveClip &clip)
PlayableTrackControls::InitMenuData * mpData
DECLARE_POPUP_MENU(WaveColorMenuTable)
void InitUserData(void *pUserData) override
Called before the menu items are appended.
int IdOfWaveColor(int WaveColor)
Converts a WaveColor enumeration to a wxWidgets menu item Id.
void OnWaveColorChange(wxCommandEvent &event)
static WaveColorMenuTable & Instance()
WaveTrack & FindWaveTrack() const
PlayableTrackControls::InitMenuData * mpData
WavePortion(int x, int y, int w, int h, double zoom, bool i)