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