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