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