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 WaveTrackView.cpp
8
9**********************************************************************/
10
11
12#include "WaveformView.h"
13
14#include "WaveformCache.h"
16#include "WaveTrackView.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, false);
97 break;
98 }
101 view.mSampleHandle, st.state, pTrack );
102 break;
103 default:
104 result = {};
105 break;
106 }
107 if (result)
108 results.push_back(result);
109 }
110 }
111
112 return std::move( results );
113}
114
115void WaveformView::DoSetMinimized( bool minimized )
116{
117 auto wt = static_cast<WaveTrack*>( FindTrack().get() );
118
119#ifdef EXPERIMENTAL_HALF_WAVE
120 bool bHalfWave;
121 gPrefs->Read(wxT("/GUI/CollapseToHalfWave"), &bHalfWave, false);
122 if( bHalfWave )
123 {
124 auto &cache = WaveformScale::Get(*wt);
125 if (minimized)
126 // Zoom to show fractionally more than the top half of the wave.
127 cache.SetDisplayBounds( -0.01f, 1.0f );
128 else
129 // Zoom out full
130 cache.SetDisplayBounds( -1.0f, 1.0f );
131 }
132#endif
133
134 TrackView::DoSetMinimized( minimized );
135}
136
137auto WaveformView::SubViewType() const -> const Type &
138{
139 return sType;
140}
141
142std::shared_ptr<TrackVRulerControls> WaveformView::DoGetVRulerControls()
143{
144 return std::make_shared<WaveformVRulerControls>( shared_from_this() );
145}
146
147namespace
148{
149
151 int leftOffset, const wxRect &rect,
152 const double env[],
153 float zoomMin, float zoomMax,
154 int zeroLevelYCoordinate,
155 bool dB, float dBRange,
156 double t0, double t1,
157 bool bIsSyncLockSelected,
158 bool highlightEnvelope)
159{
160 auto &dc = context.dc;
161 const auto artist = TrackArtist::Get( context );
162 const auto &zoomInfo = *artist->pZoomInfo;
163
164 // Visually (one vertical slice of the waveform background, on its side;
165 // the "*" is the actual waveform background we're drawing
166 //
167 //1.0 0.0 -1.0
168 // |--------------------------------|--------------------------------|
169 // *************** ***************
170 // | | | |
171 // maxtop maxbot mintop minbot
172
173 int h = rect.height;
174 int halfHeight = wxMax(h / 2, 1);
175 int maxtop, lmaxtop = 0;
176 int mintop, lmintop = 0;
177 int maxbot, lmaxbot = 0;
178 int minbot, lminbot = 0;
179 bool sel, lsel = false;
180 int xx, lx = 0;
181 int l, w;
182
183 const auto &blankBrush = artist->blankBrush;
184 const auto &selectedBrush = artist->selectedBrush;
185 const auto &unselectedBrush = artist->unselectedBrush;
186
187 dc.SetPen(*wxTRANSPARENT_PEN);
188 dc.SetBrush(blankBrush);
189 dc.DrawRectangle(rect);
190
191 // Bug 2389 - always draw at least one pixel of selection.
192 int selectedX = zoomInfo.TimeToPosition(t0, -leftOffset);
193
194 double time = zoomInfo.PositionToTime(0, -leftOffset), nextTime;
195 for (xx = 0; xx < rect.width; ++xx, time = nextTime) {
196 nextTime = zoomInfo.PositionToTime(xx + 1, -leftOffset);
197 // First we compute the truncated shape of the waveform background.
198 // If drawEnvelope is true, then we compute the lower border of the
199 // envelope.
200
201 maxtop = GetWaveYPos(env[xx], zoomMin, zoomMax,
202 h, dB, true, dBRange, true);
203 maxbot = GetWaveYPos(env[xx], zoomMin, zoomMax,
204 h, dB, false, dBRange, true);
205
206 mintop = GetWaveYPos(-env[xx], zoomMin, zoomMax,
207 h, dB, false, dBRange, true);
208 minbot = GetWaveYPos(-env[xx], zoomMin, zoomMax,
209 h, dB, true, dBRange, true);
210
211 // Make sure it's odd so that a that max and min mirror each other
212 mintop +=1;
213 minbot +=1;
214
215 const auto drawEnvelope = artist->drawEnvelope;
216 if (!drawEnvelope || maxbot > mintop) {
217 maxbot = halfHeight;
218 mintop = halfHeight;
219 }
220
221 sel = (t0 <= time && nextTime < t1);
222 sel = sel || (xx == selectedX);
223 // We don't draw selection color for sync-lock selected tracks.
224 sel = sel && !bIsSyncLockSelected;
225
226 if (lmaxtop == maxtop &&
227 lmintop == mintop &&
228 lmaxbot == maxbot &&
229 lminbot == minbot &&
230 lsel == sel) {
231 continue;
232 }
233
234 dc.SetBrush(lsel ? selectedBrush : unselectedBrush);
235
236 l = rect.x + lx;
237 w = xx - lx;
238 if (lmaxbot < lmintop - 1) {
239 dc.DrawRectangle(l, rect.y + lmaxtop, w, lmaxbot - lmaxtop);
240 dc.DrawRectangle(l, rect.y + lmintop, w, lminbot - lmintop);
241 }
242 else {
243 dc.DrawRectangle(l, rect.y + lmaxtop, w, lminbot - lmaxtop);
244 }
245
246 if (highlightEnvelope && lmaxbot < lmintop - 1) {
247 dc.SetBrush( AColor::uglyBrush );
248 dc.DrawRectangle(l, rect.y + lmaxbot, w, lmintop - lmaxbot);
249 }
250
251 lmaxtop = maxtop;
252 lmintop = mintop;
253 lmaxbot = maxbot;
254 lminbot = minbot;
255 lsel = sel;
256 lx = xx;
257 }
258
259 dc.SetBrush(lsel ? selectedBrush : unselectedBrush);
260 l = rect.x + lx;
261 w = xx - lx;
262 if (lmaxbot < lmintop - 1) {
263 dc.DrawRectangle(l, rect.y + lmaxtop, w, lmaxbot - lmaxtop);
264 dc.DrawRectangle(l, rect.y + lmintop, w, lminbot - lmintop);
265 }
266 else {
267 dc.DrawRectangle(l, rect.y + lmaxtop, w, lminbot - lmaxtop);
268 }
269 if (highlightEnvelope && lmaxbot < lmintop - 1) {
270 dc.SetBrush( AColor::uglyBrush );
271 dc.DrawRectangle(l, rect.y + lmaxbot, w, lmintop - lmaxbot);
272 }
273
274 // If sync-lock selected, draw in linked graphics.
275 if (bIsSyncLockSelected && t0 < t1) {
276 const int begin = std::max(0, std::min(rect.width, (int)(zoomInfo.TimeToPosition(t0, -leftOffset))));
277 const int end = std::max(0, std::min(rect.width, (int)(zoomInfo.TimeToPosition(t1, -leftOffset))));
279 { rect.x + begin, rect.y, end - 1 - begin, rect.height } );
280 }
281
282 //OK, the display bounds are between min and max, which
283 //is spread across rect.height. Draw the line at the proper place.
284 if (zeroLevelYCoordinate >= rect.GetTop() &&
285 zeroLevelYCoordinate <= rect.GetBottom()) {
286 dc.SetPen(*wxBLACK_PEN);
287 AColor::Line(dc, rect.x, zeroLevelYCoordinate,
288 rect.x + rect.width - 1, zeroLevelYCoordinate);
289 }
290}
291
293 wxRect rect;
296 WavePortion(int x, int y, int w, int h, double zoom, bool i)
297 : rect(x, y, w, h), averageZoom(zoom), inFisheye(i)
298 {}
299};
300
302 (std::vector<WavePortion> &portions, const wxRect &rect, const ZoomInfo &zoomInfo,
303 const ClipParameters &params)
304{
305 // If there is no fisheye, then only one rectangle has nonzero width.
306 // If there is a fisheye, make rectangles for before and after
307 // (except when they are squeezed to zero width), and at least one for inside
308 // the fisheye.
309
310 ZoomInfo::Intervals intervals;
311 zoomInfo.FindIntervals(params.rate, intervals, rect.width, rect.x);
312 ZoomInfo::Intervals::const_iterator it = intervals.begin(), end = intervals.end(), prev;
313 wxASSERT(it != end && it->position == rect.x);
314 const int rightmost = rect.x + rect.width;
315 for (int left = rect.x; left < rightmost;) {
316 while (it != end && it->position <= left)
317 prev = it++;
318 if (it == end)
319 break;
320 const int right = std::max(left, (int)(it->position));
321 const int width = right - left;
322 if (width > 0)
323 portions.push_back(
324 WavePortion(left, rect.y, width, rect.height,
325 prev->averageZoom, prev->inFisheye)
326 );
327 left = right;
328 }
329}
330
332 TrackPanelDrawingContext &context, const wxRect & rect, const double env[],
333 float zoomMin, float zoomMax,
334 bool dB, float dBRange,
335 const float *min, const float *max, const float *rms, const int *bl,
336 bool muted)
337{
338 auto &dc = context.dc;
339
340 // Display a line representing the
341 // min and max of the samples in this region
342 int lasth1 = std::numeric_limits<int>::max();
343 int lasth2 = std::numeric_limits<int>::min();
344 int h1;
345 int h2;
346 ArrayOf<int> r1{ size_t(rect.width) };
347 ArrayOf<int> r2{ size_t(rect.width) };
348 ArrayOf<int> clipped;
349 int clipcnt = 0;
350
351 const auto artist = TrackArtist::Get( context );
352 const auto bShowClipping = artist->mShowClipping;
353 if (bShowClipping) {
354 clipped.reinit( size_t(rect.width) );
355 }
356
357 long pixAnimOffset = (long)fabs((double)(wxDateTime::Now().GetTicks() * -10)) +
358 wxDateTime::Now().GetMillisecond() / 100; //10 pixels a second
359
360 const auto ms = wxDateTime::Now().GetMillisecond();
361 const auto ticks = (long)fabs((double)(wxDateTime::Now().GetTicks() * -10));
362
363 bool drawStripes = true;
364 bool drawWaveform = true;
365
366 const auto &muteSamplePen = artist->muteSamplePen;
367 const auto &samplePen = artist->samplePen;
368
369 dc.SetPen(muted ? muteSamplePen : samplePen);
370 for (int x0 = 0; x0 < rect.width; ++x0) {
371 int xx = rect.x + x0;
372 double v;
373 v = min[x0] * env[x0];
374 if (clipped && bShowClipping && (v <= -MAX_AUDIO))
375 {
376 if (clipcnt == 0 || clipped[clipcnt - 1] != xx) {
377 clipped[clipcnt++] = xx;
378 }
379 }
380 h1 = GetWaveYPos(v, zoomMin, zoomMax,
381 rect.height, dB, true, dBRange, true);
382
383 v = max[x0] * env[x0];
384 if (clipped && bShowClipping && (v >= MAX_AUDIO))
385 {
386 if (clipcnt == 0 || clipped[clipcnt - 1] != xx) {
387 clipped[clipcnt++] = xx;
388 }
389 }
390 h2 = GetWaveYPos(v, zoomMin, zoomMax,
391 rect.height, dB, true, dBRange, true);
392
393 // JKC: This adjustment to h1 and h2 ensures that the drawn
394 // waveform is continuous.
395 if (x0 > 0) {
396 if (h1 < lasth2) {
397 h1 = lasth2 - 1;
398 }
399 if (h2 > lasth1) {
400 h2 = lasth1 + 1;
401 }
402 }
403 lasth1 = h1;
404 lasth2 = h2;
405
406 r1[x0] = GetWaveYPos(-rms[x0] * env[x0], zoomMin, zoomMax,
407 rect.height, dB, true, dBRange, true);
408 r2[x0] = GetWaveYPos(rms[x0] * env[x0], zoomMin, zoomMax,
409 rect.height, dB, true, dBRange, true);
410 // Make sure the rms isn't larger than the waveform min/max
411 if (r1[x0] > h1 - 1) {
412 r1[x0] = h1 - 1;
413 }
414 if (r2[x0] < h2 + 1) {
415 r2[x0] = h2 + 1;
416 }
417 if (r2[x0] > r1[x0]) {
418 r2[x0] = r1[x0];
419 }
420
421 if (bl[x0] <= -1) {
422 if (drawStripes) {
423 // TODO:unify with buffer drawing.
424 dc.SetPen((bl[x0] % 2) ? muteSamplePen : samplePen);
425 for (int yy = 0; yy < rect.height / 25 + 1; ++yy) {
426 // we are drawing over the buffer, but I think DrawLine takes care of this.
427 AColor::Line(dc,
428 xx,
429 rect.y + 25 * yy + (x0 /*+pixAnimOffset*/) % 25,
430 xx,
431 rect.y + 25 * yy + (x0 /*+pixAnimOffset*/) % 25 + 6); //take the min so we don't draw past the edge
432 }
433 }
434
435 // draw a dummy waveform - some kind of sinusoid. We want to animate it so the user knows it's a dummy. Use the second's unit of a get time function.
436 // Lets use a triangle wave for now since it's easier - I don't want to use sin() or make a wavetable just for this.
437 if (drawWaveform) {
438 int triX;
439 dc.SetPen(samplePen);
440 triX = fabs((double)((x0 + pixAnimOffset) % (2 * rect.height)) - rect.height) + rect.height;
441 for (int yy = 0; yy < rect.height; ++yy) {
442 if ((yy + triX) % rect.height == 0) {
443 dc.DrawPoint(xx, rect.y + yy);
444 }
445 }
446 }
447
448 // Restore the pen for remaining pixel columns!
449 dc.SetPen(muted ? muteSamplePen : samplePen);
450 }
451 else {
452 AColor::Line(dc, xx, rect.y + h2, xx, rect.y + h1);
453 }
454 }
455
456 // Stroke rms over the min-max
457 const auto &muteRmsPen = artist->muteRmsPen;
458 const auto &rmsPen = artist->rmsPen;
459
460 dc.SetPen(muted ? muteRmsPen : rmsPen);
461 for (int x0 = 0; x0 < rect.width; ++x0) {
462 int xx = rect.x + x0;
463 if (bl[x0] <= -1) {
464 }
465 else if (r1[x0] != r2[x0]) {
466 AColor::Line(dc, xx, rect.y + r2[x0], xx, rect.y + r1[x0]);
467 }
468 }
469
470 // Draw the clipping lines
471 if (clipcnt) {
472 const auto &muteClippedPen = artist->muteClippedPen;
473 const auto &clippedPen = artist->clippedPen;
474
475 dc.SetPen(muted ? muteClippedPen : clippedPen);
476 while (--clipcnt >= 0) {
477 int xx = clipped[clipcnt];
478 AColor::Line(dc, xx, rect.y, xx, rect.y + rect.height);
479 }
480 }
481}
482
484 int leftOffset, const wxRect &rect,
485 float zoomMin, float zoomMax,
486 bool dB, float dBRange,
487 const WaveClip *clip,
488 bool showPoints, bool muted,
489 bool highlight)
490{
491 auto &dc = context.dc;
492 const auto artist = TrackArtist::Get( context );
493 const auto &zoomInfo = *artist->pZoomInfo;
494
495 const double toffset = clip->GetPlayStartTime();
496 double rate = clip->GetRate();
497 const double t0 = std::max(0.0, zoomInfo.PositionToTime(0, -leftOffset) - toffset);
498 const auto s0 = sampleCount(floor(t0 * rate));
499 const auto snSamples = clip->GetPlaySamplesCount();
500 if (s0 > snSamples)
501 return;
502
503 const double t1 = zoomInfo.PositionToTime(rect.width - 1, -leftOffset) - toffset;
504 const auto s1 = sampleCount(ceil(t1 * rate));
505
506 // Assume size_t will not overflow, else we wouldn't be here drawing the
507 // few individual samples
508 auto slen = std::min(snSamples - s0, s1 - s0 + 1).as_size_t();
509
510 if (slen <= 0)
511 return;
512
513 Floats buffer{ size_t(slen) };
514 clip->GetSamples((samplePtr)buffer.get(), floatSample, s0, slen,
515 // Suppress exceptions in this drawing operation:
516 false);
517
518 ArrayOf<int> xpos{ size_t(slen) };
519 ArrayOf<int> ypos{ size_t(slen) };
520 ArrayOf<int> clipped;
521 int clipcnt = 0;
522
523 const auto bShowClipping = artist->mShowClipping;
524 if (bShowClipping)
525 clipped.reinit( size_t(slen) );
526
527 const auto &muteSamplePen = artist->muteSamplePen;
528 const auto &samplePen = artist->samplePen;
529 auto &pen = highlight ? AColor::uglyPen : muted ? muteSamplePen : samplePen;
530 dc.SetPen( pen );
531
532 for (decltype(slen) s = 0; s < slen; s++) {
533 const double time = toffset + (s + s0).as_double() / rate;
534 const int xx = // An offset into the rectangle rect
535 std::max(-10000, std::min(10000,
536 (int)(zoomInfo.TimeToPosition(time, -leftOffset))));
537 xpos[s] = xx;
538
539 // Calculate sample as it would be rendered, so quantize time
540 double value =
541 clip->GetEnvelope()->GetValue( time, 1.0 / clip->GetRate() );
542 const double tt = buffer[s] * value;
543
544 if (clipped && bShowClipping && ((tt <= -MAX_AUDIO) || (tt >= MAX_AUDIO)))
545 clipped[clipcnt++] = xx;
546 ypos[s] =
547 std::max(-1,
548 std::min(rect.height,
549 GetWaveYPos(tt, zoomMin, zoomMax,
550 rect.height, dB, true, dBRange, false)));
551 }
552
553
554 if (showPoints) {
555 // Draw points where spacing is enough
556 const auto bigPoints = artist->bigPoints;
557 const int tickSize = bigPoints ? 4 : 3;// Bigger ellipses when draggable.
558 wxRect pr;
559 pr.width = tickSize;
560 pr.height = tickSize;
561 //different colour when draggable.
562 const auto &dragsampleBrush = artist->dragsampleBrush;
563 const auto &sampleBrush = artist->sampleBrush;
564 auto &brush = highlight
566 : bigPoints ? dragsampleBrush : sampleBrush;
567 dc.SetBrush( brush );
568 for (decltype(slen) s = 0; s < slen; s++) {
569 if (ypos[s] >= 0 && ypos[s] < rect.height) {
570 pr.x = rect.x + xpos[s] - tickSize/2;
571 pr.y = rect.y + ypos[s] - tickSize/2;
572 dc.DrawEllipse(pr);
573 }
574 }
575 }
576
577 const auto sampleDisplay = artist->mSampleDisplay;
578 if (showPoints && (sampleDisplay == (int) WaveTrackViewConstants::StemPlot)) {
579 // Draw vertical lines
580 int yZero = GetWaveYPos(0.0, zoomMin, zoomMax, rect.height, dB, true, dBRange, false);
581 yZero = rect.y + std::max(-1, std::min(rect.height, yZero));
582 for (decltype(slen) s = 0; s < slen; s++) {
583 AColor::Line(dc,
584 rect.x + xpos[s], rect.y + ypos[s],
585 rect.x + xpos[s], yZero);
586 }
587 }
588 else {
589 // Connect samples with straight lines
590 for (decltype(slen) s = 0; s < slen - 1; s++) {
591 AColor::Line(dc,
592 rect.x + xpos[s], rect.y + ypos[s],
593 rect.x + xpos[s + 1], rect.y + ypos[s + 1]);
594 }
595 }
596
597 // Draw clipping
598 if (clipcnt) {
599 const auto &muteClippedPen = artist->muteClippedPen;
600 const auto &clippedPen = artist->clippedPen;
601 dc.SetPen(muted ? muteClippedPen : clippedPen);
602 while (--clipcnt >= 0) {
603 auto s = clipped[clipcnt];
604 AColor::Line(dc, rect.x + s, rect.y, rect.x + s, rect.y + rect.height);
605 }
606 }
607}
608
611 const wxRect &rect, int x0, int y0, int cy, bool top )
612{
613 auto &dc = context.dc;
614
615 int xx = rect.x + x0;
616 int yy = rect.y + cy;
617
618 if (y0 < 0) {
619 if (x0 % 4 != 3) {
620 AColor::Line(dc, xx, yy, xx, yy + 3);
621 }
622 }
623 else if (y0 > rect.height) {
624 if (x0 % 4 != 3) {
625 AColor::Line(dc, xx, yy - 3, xx, yy);
626 }
627 }
628 else {
629 if (top) {
630 AColor::Line(dc, xx, yy, xx, yy + 3);
631 }
632 else {
633 AColor::Line(dc, xx, yy - 3, xx, yy);
634 }
635 }
636}
637
639 const wxRect &rect, const double env[],
640 float zoomMin, float zoomMax,
641 bool dB, float dBRange, bool highlight)
642{
643 auto &dc = context.dc;
644
645 int h = rect.height;
646
647 auto &pen = highlight ? AColor::uglyPen : AColor::envelopePen;
648 dc.SetPen( pen );
649
650 for (int x0 = 0; x0 < rect.width; ++x0) {
651 int cenvTop = GetWaveYPos(env[x0], zoomMin, zoomMax,
652 h, dB, true, dBRange, true);
653
654 int cenvBot = GetWaveYPos(-env[x0], zoomMin, zoomMax,
655 h, dB, true, dBRange, true);
656
657 int envTop = GetWaveYPos(env[x0], zoomMin, zoomMax,
658 h, dB, true, dBRange, false);
659
660 int envBot = GetWaveYPos(-env[x0], zoomMin, zoomMax,
661 h, dB, true, dBRange, false);
662
663 // Make the collision at zero actually look solid
664 if (cenvBot - cenvTop < 9) {
665 int value = (int)((zoomMax / (zoomMax - zoomMin)) * h);
666 cenvTop = value - 4;
667 cenvBot = value + 4;
668 }
669
670 DrawEnvLine( context, rect, x0, envTop, cenvTop, true );
671 DrawEnvLine( context, rect, x0, envBot, cenvBot, false );
672 }
673}
674
675// Headers needed only for experimental drawing below
676//#include "tracks/playabletrack/wavetrack/ui/SampleHandle.h"
677//#include "tracks/ui/EnvelopeHandle.h"
679 const WaveTrack *track,
680 const WaveClip *clip,
681 const wxRect & rect,
682 bool dB,
683 bool muted,
684 bool selected)
685{
686 auto &dc = context.dc;
687 const auto artist = TrackArtist::Get( context );
688 const auto &selectedRegion = *artist->pSelectedRegion;
689 const auto &zoomInfo = *artist->pZoomInfo;
690
692
693 bool highlightEnvelope = false;
694#ifdef EXPERIMENTAL_TRACK_PANEL_HIGHLIGHTING
695 auto target = dynamic_cast<EnvelopeHandle*>(context.target.get());
696 highlightEnvelope = target && target->GetEnvelope() == clip->GetEnvelope();
697#endif
698
699 //If clip is "too small" draw a placeholder instead of
700 //attempting to fit the contents into a few pixels
701 if (!WaveTrackView::ClipDetailsVisible(*clip, zoomInfo, rect))
702 {
703 auto clipRect = ClipParameters::GetClipRect(*clip, zoomInfo, rect);
704 TrackArt::DrawClipFolded(dc, clipRect);
705 return;
706 }
707
709 false, track, clip, rect, selectedRegion, zoomInfo };
710 const wxRect &hiddenMid = params.hiddenMid;
711 // The "hiddenMid" rect contains the part of the display actually
712 // containing the waveform, as it appears without the fisheye. If it's empty, we're done.
713 if (hiddenMid.width <= 0) {
714 return;
715 }
716
717 const double &t0 = params.t0;
718 const double &tOffset = params.tOffset;
719 const double &h = params.h;
720 const double &tpre = params.tpre;
721 const double &tpost = params.tpost;
722 const double &t1 = params.t1;
723 const double &averagePixelsPerSample = params.averagePixelsPerSample;
724 const double &rate = params.rate;
725 double leftOffset = params.leftOffset;
726 const wxRect &mid = params.mid;
727
728 auto &settings = WaveformSettings::Get(*track);
729 const float dBRange = settings.dBRange;
730
731 dc.SetPen(*wxTRANSPARENT_PEN);
732 int iColorIndex = clip->GetColourIndex();
733 artist->SetColours( iColorIndex );
734
735 // The bounds (controlled by vertical zooming; -1.0...1.0
736 // by default)
737 float zoomMin, zoomMax;
738 auto &cache = WaveformScale::Get(*track);
739 cache.GetDisplayBounds(zoomMin, zoomMax);
740
741 std::vector<double> vEnv(mid.width);
742 double *const env = &vEnv[0];
744 tOffset,
745
746 // PRL: change back to make envelope evaluate only at sample times
747 // and then interpolate the display
748 0, // 1.0 / rate,
749
750 env, mid.width, leftOffset, zoomInfo );
751
752 // Draw the background of the track, outlining the shape of
753 // the envelope and using a colored pen for the selected
754 // part of the waveform
755 {
756 double tt0, tt1;
758 tt0 = track->LongSamplesToTime(track->TimeToLongSamples(selectedRegion.t0())),
759 tt1 = track->LongSamplesToTime(track->TimeToLongSamples(selectedRegion.t1()));
760 }
761 else
762 tt0 = tt1 = 0.0;
763 DrawWaveformBackground(context, leftOffset, mid,
764 env,
765 zoomMin, zoomMax,
766 cache.ZeroLevelYCoordinate(mid),
767 dB, dBRange,
768 tt0, tt1,
769 !track->GetSelected(), highlightEnvelope);
770 }
771
772 WaveDisplay display(hiddenMid.width);
773
774 const double pps =
775 averagePixelsPerSample * rate;
776
777 // For each portion separately, we will decide to draw
778 // it as min/max/rms or as individual samples.
779 std::vector<WavePortion> portions;
780 FindWavePortions(portions, rect, zoomInfo, params);
781 const unsigned nPortions = portions.size();
782
783 // Require at least 1/2 pixel per sample for drawing individual samples.
784 const double threshold1 = 0.5 * rate;
785 // Require at least 3 pixels per sample for drawing the draggable points.
786 const double threshold2 = 3 * rate;
787
788 auto &clipCache = WaveClipWaveformCache::Get(*clip);
789
790 {
791 bool showIndividualSamples = false;
792 for (unsigned ii = 0; !showIndividualSamples && ii < nPortions; ++ii) {
793 const WavePortion &portion = portions[ii];
794 showIndividualSamples =
795 !portion.inFisheye && portion.averageZoom > threshold1;
796 }
797
798 if (!showIndividualSamples) {
799 // The WaveClip class handles the details of computing the shape
800 // of the waveform. The only way GetWaveDisplay will fail is if
801 // there's a serious error, like some of the waveform data can't
802 // be loaded. So if the function returns false, we can just exit.
803
804 // Note that we compute the full width display even if there is a
805 // fisheye hiding part of it, because of the caching. If the
806 // fisheye moves over the background, there is then less to do when
807 // redrawing.
808
809 if (!clipCache.GetWaveDisplay( *clip, display,
810 t0, pps))
811 return;
812 }
813 }
814
815 // TODO Add a comment to say what this loop does.
816 // Possibly make it into a subroutine.
817 for (unsigned ii = 0; ii < nPortions; ++ii) {
818 WavePortion &portion = portions[ii];
819 const bool showIndividualSamples = portion.averageZoom > threshold1;
820 const bool showPoints = portion.averageZoom > threshold2;
821 wxRect& rectPortion = portion.rect;
822 rectPortion.Intersect(mid);
823 wxASSERT(rectPortion.width >= 0);
824
825 float *useMin = 0, *useMax = 0, *useRms = 0;
826 int *useBl = 0;
827 WaveDisplay fisheyeDisplay(rectPortion.width);
828 int skipped = 0, skippedLeft = 0, skippedRight = 0;
829 if (portion.inFisheye) {
830 if (!showIndividualSamples) {
831 fisheyeDisplay.Allocate();
832 const auto numSamples = clip->GetPlaySamplesCount();
833 // Get wave display data for different magnification
834 int jj = 0;
835 for (; jj < rectPortion.width; ++jj) {
836 const double time =
837 zoomInfo.PositionToTime(jj, -leftOffset) - tOffset;
838 const auto sample = (sampleCount)floor(time * rate + 0.5);
839 if (sample < 0) {
840 ++rectPortion.x;
841 ++skippedLeft;
842 continue;
843 }
844 if (sample >= numSamples)
845 break;
846 fisheyeDisplay.where[jj - skippedLeft] = sample;
847 }
848
849 skippedRight = rectPortion.width - jj;
850 skipped = skippedRight + skippedLeft;
851 rectPortion.width -= skipped;
852
853 // where needs a sentinel
854 if (jj > 0)
855 fisheyeDisplay.where[jj - skippedLeft] =
856 1 + fisheyeDisplay.where[jj - skippedLeft - 1];
857 fisheyeDisplay.width -= skipped;
858 // Get a wave display for the fisheye, uncached.
859 if (rectPortion.width > 0)
860 if (!clipCache.GetWaveDisplay( *clip,
861 fisheyeDisplay, t0, -1.0)) // ignored
862 continue; // serious error. just don't draw??
863 useMin = fisheyeDisplay.min;
864 useMax = fisheyeDisplay.max;
865 useRms = fisheyeDisplay.rms;
866 useBl = fisheyeDisplay.bl;
867 }
868 }
869 else {
870 const int pos = leftOffset - params.hiddenLeftOffset;
871 useMin = display.min + pos;
872 useMax = display.max + pos;
873 useRms = display.rms + pos;
874 useBl = display.bl + pos;
875 }
876
877 leftOffset += skippedLeft;
878
879 if (rectPortion.width > 0) {
880 if (!showIndividualSamples) {
881 std::vector<double> vEnv2(rectPortion.width);
882 double *const env2 = &vEnv2[0];
884 tOffset,
885
886 // PRL: change back to make envelope evaluate only at sample times
887 // and then interpolate the display
888 0, // 1.0 / rate,
889
890 env2, rectPortion.width, leftOffset, zoomInfo );
891
892 DrawMinMaxRMS( context, rectPortion, env2,
893 zoomMin, zoomMax,
894 dB, dBRange,
895 useMin, useMax, useRms, useBl, muted );
896 }
897 else {
898 bool highlight = false;
899#ifdef EXPERIMENTAL_TRACK_PANEL_HIGHLIGHTING
900 auto target = dynamic_cast<SampleHandle*>(context.target.get());
901 highlight = target && target->GetTrack().get() == track;
902#endif
904 context, leftOffset, rectPortion, zoomMin, zoomMax,
905 dB, dBRange,
906 clip,
907 showPoints, muted, highlight );
908 }
909 }
910
911 leftOffset += rectPortion.width + skippedRight;
912 }
913
914 const auto drawEnvelope = artist->drawEnvelope;
915 if (drawEnvelope) {
917 context, mid, env, zoomMin, zoomMax, dB, dBRange, highlightEnvelope );
919 context, mid, dB, dBRange, zoomMin, zoomMax, true, rect.x - mid.x );
920 }
921
922 // Draw arrows on the left side if the track extends to the left of the
923 // beginning of time. :)
924 if (h == 0.0 && tOffset < 0.0) {
926 }
927 {
928 auto clipRect = ClipParameters::GetClipRect(*clip, zoomInfo, rect);
929 TrackArt::DrawClipEdges(dc, clipRect, selected);
930 }
931}
932
934 const wxRect & rect,
935 bool rightwards, bool highlight )
936{
937 auto &dc = context.dc;
938
939 const int border = 3; // 3 pixels all round.
940 const int width = 6; // width of the drag box.
941 const int taper = 6; // how much the box tapers by.
942 const int barSpacing = 4; // how far apart the bars are.
943 const int barWidth = 3;
944 const int xFlat = 3;
945
946 //Enough space to draw in?
947 if (rect.height <= ((taper+border + barSpacing) * 2)) {
948 return;
949 }
950 if (rect.width <= (width * 2 + border * 3)) {
951 return;
952 }
953
954 // The draggable box is tapered towards the direction you drag it.
955 int leftTaper = rightwards ? 0 : 6;
956 int rightTaper = rightwards ? 6 : 0;
957
958 int xLeft = rightwards ? (rect.x + border - 2)
959 : (rect.x + rect.width + 1 - (border + width));
960 int yTop = rect.y + border;
961 int yBot = rect.y + rect.height - border - 1;
962
963 AColor::Light(&dc, false, highlight);
964 AColor::Line(dc, xLeft, yBot - leftTaper, xLeft, yTop + leftTaper);
965 AColor::Line(dc, xLeft, yTop + leftTaper, xLeft + xFlat, yTop);
966 AColor::Line(dc, xLeft + xFlat, yTop, xLeft + width, yTop + rightTaper);
967
968 AColor::Dark(&dc, false, highlight);
969 AColor::Line(dc, xLeft + width, yTop + rightTaper, xLeft + width, yBot - rightTaper);
970 AColor::Line(dc, xLeft + width, yBot - rightTaper, xLeft + width-xFlat, yBot);
971 AColor::Line(dc, xLeft + width - xFlat, yBot, xLeft, yBot - leftTaper);
972
973 int firstBar = yTop + taper + taper / 2;
974 int nBars = (yBot - yTop - taper * 3) / barSpacing + 1;
975 xLeft += (width - barWidth + 1) / 2;
976 int yy;
977 int i;
978
979 AColor::Light(&dc, false, highlight);
980 for (i = 0;i < nBars; i++) {
981 yy = firstBar + barSpacing * i;
982 AColor::Line(dc, xLeft, yy, xLeft + barWidth, yy);
983 }
984 AColor::Dark(&dc, false, highlight);
985 for(i = 0;i < nBars; i++){
986 yy = firstBar + barSpacing * i + 1;
987 AColor::Line(dc, xLeft, yy, xLeft + barWidth, yy);
988 }
989}
990
991}
992
993// Header needed only for experimental drawing below
994//#include "tracks/ui/TimeShiftHandle.h"
996 const WaveTrack *track,
997 const WaveClip* selectedClip,
998 const wxRect& rect,
999 bool muted)
1000{
1001 auto &dc = context.dc;
1002 const auto artist = TrackArtist::Get( context );
1003
1004 bool highlight = false;
1005 bool gripHit = false;
1006#ifdef EXPERIMENTAL_TRACK_PANEL_HIGHLIGHTING
1007 auto target = dynamic_cast<TimeShiftHandle*>(context.target.get());
1008 gripHit = target && target->IsGripHit();
1009 highlight = target && target->GetTrack().get() == track;
1010#endif
1011
1012 const bool dB = !WaveformSettings::Get(*track).isLinear();
1013
1014 const auto &blankSelectedBrush = artist->blankSelectedBrush;
1015 const auto &blankBrush = artist->blankBrush;
1017 context, rect, track, blankSelectedBrush, blankBrush );
1018
1019 for (const auto& clip : track->GetClips())
1020 {
1021 DrawClipWaveform(context, track, clip.get(), rect,
1022 dB, muted, clip.get() == selectedClip);
1023 }
1024 DrawBoldBoundaries( context, track, rect );
1025
1026 const auto drawSliders = artist->drawSliders;
1027 if (drawSliders) {
1028 DrawTimeSlider( context, rect, true, highlight && gripHit ); // directed right
1029 DrawTimeSlider( context, rect, false, highlight && gripHit ); // directed left
1030 }
1031}
1032
1034 TrackPanelDrawingContext &context, const wxRect &rect, unsigned iPass )
1035{
1036 if ( iPass == TrackArtist::PassTracks ) {
1037 auto &dc = context.dc;
1038 // Update cache for locations, e.g. cutlines and merge points
1039 // Bug2588: do this for both channels, even if one is not drawn, so that
1040 // cut-line editing (which depends on the locations cache) works properly.
1041 // If both channels are visible, we will duplicate this effort, but that
1042 // matters little.
1043 for( auto channel:
1044 TrackList::Channels(static_cast<WaveTrack*>(FindTrack().get())) ) {
1045 auto &locationsCache = WaveTrackLocations::Get( *channel );
1046 locationsCache.Update( *channel );
1047 }
1048
1049 const auto wt = std::static_pointer_cast<const WaveTrack>(
1050 FindTrack()->SubstitutePendingChangedTrack());
1051
1052 const auto artist = TrackArtist::Get( context );
1053 const auto hasSolo = artist->hasSolo;
1054 bool muted = (hasSolo || wt->GetMute()) &&
1055 !wt->GetSolo();
1056
1057#if defined(__WXMAC__)
1058 wxAntialiasMode aamode = dc.GetGraphicsContext()->GetAntialiasMode();
1059 dc.GetGraphicsContext()->SetAntialiasMode(wxANTIALIAS_NONE);
1060#endif
1061
1062 auto waveTrackView = GetWaveTrackView().lock();
1063 wxASSERT(waveTrackView.use_count());
1064
1065 auto selectedClip = waveTrackView->GetSelectedClip().lock();
1066 DoDraw(context, wt.get(), selectedClip.get(), rect, muted);
1067
1068#if defined(__WXMAC__)
1069 dc.GetGraphicsContext()->SetAntialiasMode(aamode);
1070#endif
1071 }
1072 WaveTrackSubView::Draw( context, rect, iPass );
1073}
1074
1076 []( WaveTrackView &view ){
1077 return std::make_shared< WaveformView >( view );
1078 }
1079};
1080
1081// The following attaches the wave color sub-menu to the wave track popup
1082// menu. It is appropriate only to waveform view and so is kept in this
1083// source file with the rest of the waveform view implementation.
1084
1085#include <mutex> // for std::call_once
1086#include "WaveTrackControls.h"
1087#include "../../../../widgets/PopupMenuTable.h"
1088#include "ProjectAudioIO.h"
1089#include "ProjectHistory.h"
1090#include "../../../../RefreshCode.h"
1091
1092//=============================================================================
1093// Table class for a sub-menu
1095{
1096 WaveColorMenuTable() : PopupMenuTable{ "WaveColor", XO("&Wave Color") } {}
1098
1099 static WaveColorMenuTable &Instance();
1100
1101 void InitUserData(void *pUserData) override;
1102
1104
1105 int IdOfWaveColor(int WaveColor);
1106 void OnWaveColorChange(wxCommandEvent & event);
1107
1109};
1110
1112{
1113 static WaveColorMenuTable instance;
1114 return instance;
1115}
1116
1118{
1119 mpData = static_cast<PlayableTrackControls::InitMenuData*>(pUserData);
1120}
1121
1122namespace {
1123using ValueFinder = std::function< int( WaveTrack& ) >;
1124
1126{
1127 return XXO("Instrument %i").Format( colorIndex+1 );
1128}
1129}
1130
1132 static const auto fn = []( PopupMenuHandler &handler, wxMenu &menu, int id ){
1133 auto &me = static_cast<WaveColorMenuTable&>( handler );
1134 auto pData = me.mpData;
1135 const auto &track = *static_cast<WaveTrack*>(pData->pTrack);
1136 auto &project = pData->project;
1137 bool unsafe = ProjectAudioIO::Get( project ).IsAudioActive();
1138
1139 menu.Check( id, id == me.IdOfWaveColor( track.GetWaveColorIndex() ) );
1140 menu.Enable( id, !unsafe );
1141 };
1142
1143 static std::once_flag flag;
1144 std::call_once( flag, [this]{
1145 auto &hostTable = GetWaveTrackMenuTable();
1146 OnInstrument1ID = hostTable.ReserveId();
1147 OnInstrument2ID = hostTable.ReserveId();
1148 OnInstrument3ID = hostTable.ReserveId();
1149 OnInstrument4ID = hostTable.ReserveId();
1150 } );
1151
1152 AppendRadioItem( "Instrument1", OnInstrument1ID,
1153 GetWaveColorStr(0), POPUP_MENU_FN( OnWaveColorChange ), fn );
1154 AppendRadioItem( "Instrument2", OnInstrument2ID,
1155 GetWaveColorStr(1), POPUP_MENU_FN( OnWaveColorChange ), fn );
1156 AppendRadioItem( "Instrument3", OnInstrument3ID,
1157 GetWaveColorStr(2), POPUP_MENU_FN( OnWaveColorChange ), fn );
1158 AppendRadioItem( "Instrument4", OnInstrument4ID,
1159 GetWaveColorStr(3), POPUP_MENU_FN( OnWaveColorChange ), fn );
1160
1162
1163
1164int WaveColorMenuTable::IdOfWaveColor(int WaveColor)
1165{ return OnInstrument1ID + WaveColor;}
1166
1169void WaveColorMenuTable::OnWaveColorChange(wxCommandEvent & event)
1170{
1171 int id = event.GetId();
1172 wxASSERT(id >= OnInstrument1ID && id <= OnInstrument4ID);
1173 const auto pTrack = static_cast<WaveTrack*>(mpData->pTrack);
1174
1175 int newWaveColor = id - OnInstrument1ID;
1176
1177 AudacityProject *const project = &mpData->project;
1178
1179 for (auto channel : TrackList::Channels(pTrack))
1180 channel->SetWaveColorIndex(newWaveColor);
1181
1182 ProjectHistory::Get( *project )
1183 .PushState(XO("Changed '%s' to %s")
1184 .Format( pTrack->GetName(), GetWaveColorStr(newWaveColor) ),
1185 XO("WaveColor Change"));
1186
1187 using namespace RefreshCode;
1189}
1190
1191namespace {
1194 { "SubViews/Extra" },
1195 std::make_unique<PopupMenuSection>( "WaveColor",
1196 // Conditionally add sub-menu for wave color, if showing waveform
1197 PopupMenuTable::Computed< WaveTrackPopupMenuTable >(
1199 const auto pTrack = &table.FindWaveTrack();
1200 const auto &view = WaveTrackView::Get( *pTrack );
1201 const auto displays = view.GetDisplays();
1202 bool hasWaveform = (displays.end() != std::find(
1203 displays.begin(), displays.end(),
1204 WaveTrackSubView::Type{ WaveTrackViewConstants::Waveform, {} }
1205 ) );
1206 if( hasWaveform )
1208 .Get(table.mpData));
1209 else
1210 return nullptr;
1211 } ) )
1212};
1213}
1214
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:563
#define END_POPUP_MENU()
#define BEGIN_POPUP_MENU(HandlerClass)
#define POPUP_MENU_FN(memFn)
FileConfig * gPrefs
Definition: Prefs.cpp:70
constexpr sampleFormat floatSample
Definition: SampleFormat.h:43
char * samplePtr
Definition: SampleFormat.h:55
int GetWaveYPos(float value, float min, float max, int height, bool dB, bool outer, float dBr, bool clip)
Definition: TrackArt.cpp:46
static Settings & settings()
Definition: TrackInfo.cpp:83
WaveTrackPopupMenuTable & GetWaveTrackMenuTable()
static const auto fn
AppendRadioItem("Instrument1", OnInstrument1ID, GetWaveColorStr(0), POPUP_MENU_FN(OnWaveColorChange), fn)
static WaveTrackSubView::Type sType
static std::once_flag flag
static WaveTrackSubViewType::RegisteredType reg
static const WaveTrackSubViews::RegisteredFactory key
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
Client code makes static instance from a factory of attachments; passes it to Get or Find as a retrie...
Definition: ClientData.h:266
std::shared_ptr< Track > FindTrack()
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 WaveTrackHitTest(std::weak_ptr< EnvelopeHandle > &holder, const wxMouseState &state, const wxRect &rect, const AudacityProject *pProject, const std::shared_ptr< WaveTrack > &wt)
static UIHandlePtr HitAnywhere(std::weak_ptr< EnvelopeHandle > &holder, Envelope *envelope, bool timeTrack)
Envelope * GetEnvelope() const
double GetValue(double t, double sampleDur=0) const
Get envelope value at time t.
Definition: Envelope.cpp:828
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< WaveTrack > GetTrack() const
Definition: SampleHandle.h:45
double LongSamplesToTime(sampleCount pos) const
Convert correctly between a number of samples and an (absolute) time in seconds.
Definition: SampleTrack.cpp:48
sampleCount TimeToLongSamples(double t0) const
Convert correctly between an (absolute) time in seconds and a number of samples.
Definition: SampleTrack.cpp:43
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:82
static auto Channels(TrackType *pTrack) -> TrackIterRange< TrackType >
Definition: Track.h:1417
virtual void Draw(TrackPanelDrawingContext &context, const wxRect &rect, unsigned iPass)
virtual void DoSetMinimized(bool isMinimized)
Definition: TrackView.cpp:141
Holds a msgid for the translation catalog; may also bind format arguments.
static ViewInfo & Get(AudacityProject &project)
Definition: ViewInfo.cpp:235
This allows multiple clips to be a part of one WaveTrack.
Definition: WaveClip.h:101
double GetPlayStartTime() const noexcept
Definition: WaveClip.cpp:889
bool GetSamples(samplePtr buffer, sampleFormat format, sampleCount start, size_t len, bool mayThrow=true) const
Definition: WaveClip.cpp:124
Envelope * GetEnvelope()
Definition: WaveClip.h:219
sampleCount GetPlaySamplesCount() const
Definition: WaveClip.cpp:921
int GetRate() const
Definition: WaveClip.h:140
int GetColourIndex() const
Definition: WaveClip.h:150
int * bl
Definition: WaveClip.h:53
float * rms
Definition: WaveClip.h:52
sampleCount * where
Definition: WaveClip.h:51
float * min
Definition: WaveClip.h:52
int width
Definition: WaveClip.h:50
float * max
Definition: WaveClip.h:52
void Allocate()
Definition: WaveClip.h:66
A Track that contains audio waveform data.
Definition: WaveTrack.h:51
WaveClipHolders & GetClips()
Definition: WaveTrack.h:322
const std::vector< Location > & Get() const
static void DrawBoldBoundaries(TrackPanelDrawingContext &context, const WaveTrack *track, const wxRect &rect)
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< WaveTrackView > GetWaveTrackView() const
static WaveTrackView & Get(WaveTrack &track)
static bool ClipDetailsVisible(const WaveClip &clip, const ZoomInfo &zoomInfo, const wxRect &viewRect)
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
std::shared_ptr< TrackVRulerControls > DoGetVRulerControls() override
static void DoDraw(TrackPanelDrawingContext &context, const WaveTrack *track, const WaveClip *selectedClip, const wxRect &rect, bool muted)
~WaveformView() override
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
void FindIntervals(double rate, Intervals &results, int64 width, int64 origin=0) const
Definition: ZoomInfo.cpp:104
std::vector< Interval > Intervals
Definition: ZoomInfo.h:136
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< BaseItem > BaseItemPtr
Definition: Registry.h:73
std::unique_ptr< IndirectItem > Indirect(const BaseItemSharedPtr &ptr)
A convenience function.
Definition: Registry.h:97
AUDACITY_DLL_API void DrawSyncLockTiles(TrackPanelDrawingContext &context, const wxRect &rect)
Definition: TrackArt.cpp:312
AUDACITY_DLL_API void DrawClipFolded(wxDC &dc, const wxRect &rect)
Definition: TrackArt.cpp:293
AUDACITY_DLL_API void DrawClipEdges(wxDC &dc, const wxRect &clipRect, bool selected=false)
Definition: TrackArt.cpp:256
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:422
AUDACITY_DLL_API void DrawNegativeOffsetTrackArrows(TrackPanelDrawingContext &context, const wxRect &rect)
Definition: TrackArt.cpp:123
void DrawClipWaveform(TrackPanelDrawingContext &context, const WaveTrack *track, const WaveClip *clip, const wxRect &rect, bool dB, bool muted, bool selected)
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, const int *bl, bool muted)
std::function< int(WaveTrack &) > ValueFinder
const TranslatableString GetWaveColorStr(int colorIndex)
void DrawIndividualSamples(TrackPanelDrawingContext &context, int leftOffset, const wxRect &rect, float zoomMin, float zoomMax, bool dB, float dBRange, const WaveClip *clip, bool showPoints, bool muted, bool highlight)
void DrawEnvLine(TrackPanelDrawingContext &context, const wxRect &rect, int x0, int y0, int cy, bool top)
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 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 WaveClip &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)