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