Audacity  2.2.2
Public Member Functions | Static Public Member Functions | Private Member Functions | Private Attributes | List of all members
TrackArtist Class Reference

This class handles the actual rendering of WaveTracks (both waveforms and spectra), NoteTracks, LabelTracks and TimeTracks. More...

#include <TrackArtist.h>

Public Member Functions

 TrackArtist ()
 
 ~TrackArtist ()
 
void SetColours (int iColorIndex)
 
void DrawTracks (TrackPanelDrawingContext &context, TrackList *tracks, Track *start, const wxRegion &reg, const wxRect &rect, const wxRect &clip, const SelectedRegion &selectedRegion, const ZoomInfo &zoomInfo, bool drawEnvelope, bool bigPoints, bool drawSliders)
 
void DrawTrack (TrackPanelDrawingContext &context, const Track *t, const wxRect &rect, const SelectedRegion &selectedRegion, const ZoomInfo &zoomInfo, bool drawEnvelope, bool bigPoints, bool drawSliders, bool hasSolo)
 
void DrawVRuler (TrackPanelDrawingContext &context, const Track *t, wxRect &rect)
 
void UpdateVRuler (const Track *t, wxRect &rect)
 
void SetMargins (int left, int top, int right, int bottom)
 
void UpdatePrefs ()
 
void SetBackgroundBrushes (wxBrush unselectedBrush, wxBrush selectedBrush, wxPen unselectedPen, wxPen selectedPen)
 

Static Public Member Functions

static void DrawSyncLockTiles (wxDC *dc, wxRect rect)
 
static void DrawBackgroundWithSelection (wxDC *dc, const wxRect &rect, const Track *track, wxBrush &selBrush, wxBrush &unselBrush, const SelectedRegion &selectedRegion, const ZoomInfo &zoomInfo)
 

Private Member Functions

void DrawWaveform (TrackPanelDrawingContext &context, const WaveTrack *track, const wxRect &rect, const SelectedRegion &selectedRegion, const ZoomInfo &zoomInfo, bool drawEnvelope, bool bigPoints, bool drawSliders, bool muted)
 
void DrawSpectrum (const WaveTrack *track, wxDC &dc, const wxRect &rect, const SelectedRegion &selectedRegion, const ZoomInfo &zoomInfo)
 
void DrawLabelTrack (TrackPanelDrawingContext &context, const LabelTrack *track, const wxRect &rect, const SelectedRegion &selectedRegion, const ZoomInfo &zoomInfo)
 
void DrawTimeTrack (TrackPanelDrawingContext &context, const TimeTrack *track, const wxRect &rect, const ZoomInfo &zoomInfo)
 
void DrawTimeSlider (wxDC &dc, const wxRect &rect, bool rightwards, bool highlight)
 
void DrawClipWaveform (TrackPanelDrawingContext &context, const WaveTrack *track, const WaveClip *clip, const wxRect &rect, const SelectedRegion &selectedRegion, const ZoomInfo &zoomInfo, bool drawEnvelope, bool bigPoints, bool dB, bool muted)
 
void DrawClipSpectrum (WaveTrackCache &cache, const WaveClip *clip, wxDC &dc, const wxRect &rect, const SelectedRegion &selectedRegion, const ZoomInfo &zoomInfo)
 
void DrawWaveformBackground (wxDC &dc, int leftOffset, const wxRect &rect, const double env[], float zoomMin, float zoomMax, int zeroLevelYCoordinate, bool dB, float dBRange, double t0, double t1, const ZoomInfo &zoomInfo, bool drawEnvelope, bool bIsSyncLockSelected, bool highlightEnvelope)
 
void DrawMinMaxRMS (wxDC &dc, 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, bool muted)
 
void DrawIndividualSamples (wxDC &dc, int leftOffset, const wxRect &rect, float zoomMin, float zoomMax, bool dB, float dBRange, const WaveClip *clip, const ZoomInfo &zoomInfo, bool bigPoints, bool showPoints, bool muted, bool highlight)
 
void DrawNegativeOffsetTrackArrows (wxDC &dc, const wxRect &rect)
 
void DrawEnvelope (wxDC &dc, const wxRect &rect, const double env[], float zoomMin, float zoomMax, bool dB, float dBRange, bool highlight)
 
void DrawEnvLine (wxDC &dc, const wxRect &rect, int x0, int y0, int cy, bool top)
 

Private Attributes

float mdBrange
 
long mShowClipping
 
int mSampleDisplay
 
bool mbShowTrackNameInWaveform
 
int mMarginLeft
 
int mMarginTop
 
int mMarginRight
 
int mMarginBottom
 
wxBrush blankBrush
 
wxBrush unselectedBrush
 
wxBrush selectedBrush
 
wxBrush sampleBrush
 
wxBrush selsampleBrush
 
wxBrush dragsampleBrush
 
wxBrush muteSampleBrush
 
wxBrush blankSelectedBrush
 
wxPen blankPen
 
wxPen unselectedPen
 
wxPen selectedPen
 
wxPen samplePen
 
wxPen rmsPen
 
wxPen muteRmsPen
 
wxPen selsamplePen
 
wxPen muteSamplePen
 
wxPen odProgressNotYetPen
 
wxPen odProgressDonePen
 
wxPen shadowPen
 
wxPen clippedPen
 
wxPen muteClippedPen
 
wxPen blankSelectedPen
 
std::unique_ptr< Rulervruler
 

Detailed Description

This class handles the actual rendering of WaveTracks (both waveforms and spectra), NoteTracks, LabelTracks and TimeTracks.

It's actually a little harder than it looks, because for waveforms at least it needs to cache the samples that are currently on-screen.

How Audacity Redisplay Works
Roger Dannenberg

Oct 2010
This is a brief guide to Audacity redisplay – it may not be complete. It is my attempt to understand the complicated graphics strategy.

One basic idea is that redrawing waveforms is rather slow, so Audacity saves waveform images in bitmaps to make redrawing faster. In particular, during audio playback (and recording), the vertical time indicator is drawn over the waveform about 20 times per second. To avoid unnecessary computation, the indicator is erased by copying a column of pixels from a bitmap image of the waveform. Notice that this implies a two-stage process: first, waveforms are drawn to the bitmp; then, the bitmap (or pieces of it) are copied to the screen, perhaps along with other graphics.

The bitmap is for the entire track panel, i.e. multiple tracks, and includes things like the Gain and Pan slders to the left of the waveform images.

The screen update uses a mixture of direct drawing and indirect paint events. The "normal" way to update a graphical display is to call the Refresh() method when something invalidates the screen. Later, the system calls OnPaint(), which the application overrides to (re)draw the screen. In wxWidgets, you can also draw directly to the screen without calling Refresh() and without waiting for OnPaint() to be called.

I would expect there to be a 2-level invalidation scheme: Some changes invalidate the bitmap, forcing a bitmap redraw and a screen redraw. Other changes merely update the screen using pre-existing bitmaps. In Audacity, the "2-level" invalidation works like this: Anything that invalidates the bitmap calls TrackPanel::Refresh(), which has an eraseBackground parameter. This flag says to redraw the bitmap when OnPaint() is called. If eraseBackground is false, the existing bitmap can be used for waveform images. Audacity also draws directly to the screen to update the time indicator during playback. To move the indicator, one column of pixels is drawn to the screen to remove the indicator. Then the indicator is drawn at a NEW time location.

The track panel consists of many components. The tree of calls that update the bitmap looks like this:

for each track,
various TrackInfo sliders and buttons
TrackPanel::DrawZooming();
draws horizontal dashed lines during zoom-drag
draws yellow highlight on selected track
draw snap guidelines if any

After drawing the bitmap and blitting the bitmap to the screen, the following calls are (sometimes) made. To keep track of what has been drawn on screen over the bitmap images,

TrackPanel::DoDrawIndicator();
copy pixel column from bitmap to screen to erase indicator line
TrackPanel::DoDrawCursor(); [if mLastCursor == mLastIndicator]
AdornedRulerPanel::DrawIndicator(); [not part of TrackPanel graphics]
draw indicator on each track
TrackPanel::DoDrawCursor();
draw cursor on each track [at selectedRegion.t0()]
AdornedRulerPanel::DrawCursor(); [not part of TrackPanel graphics]

To move the indicator, TrackPanel::OnTimer() calls the following, using a drawing context (DC) for the screen. (Refresh is not called to create an OnPaint event. Instead, drawing is direct to the screen.)

TrackPanel::DrawIndicator();
TrackPanel::DoDrawIndicator();

Notice that TrackPanel::DrawZooming(), TrackPanel::HighlightFocusedTrack(), and snap guidelines could be drawn directly to the screen rather than to the bitmap, generally eliminating redraw work.

One problem is slider udpates. Sliders are in the left area of the track panel. They are not wxWindows like wxSliders, but instead are just drawn on the TrackPanel. When slider state changes, all tracks do a full refresh, including recomputing the backing store. It would make more sense to just invalidate the region containing the slider. However, doing that would require either incrementally updating the bitmap (not currently done), or maintaining the sliders and other track info on the screen and not in the bitmap.

In my opinion, the bitmap should contain only the waveform, note, and label images along with gray selection highlights. The track info (sliders, buttons, title, etc.), track selection highlight, cursor, and indicator should be drawn in the normal way, and clipping regions should be used to avoid excessive copying of bitmaps (say, when sliders move), or excessive redrawing of track info widgets (say, when scrolling occurs). This is a fairly tricky code change since it requires careful specification of what and where redraw should take place when any state changes. One surprising finding is that NoteTrack display is slow compared to WaveTrack display. Each note takes some time to gather attributes and select colors, and while audio draws two amplitudes per horizontal pixels, large MIDI scores can have more notes than horizontal pixels. This can make slider changes very sluggish, but this can also be a problem with many audio tracks.

Definition at line 50 of file TrackArtist.h.

Constructor & Destructor Documentation

TrackArtist::TrackArtist ( )

Definition at line 267 of file TrackArtist.cpp.

References ENV_DB_RANGE, mdBrange, mMarginBottom, mMarginLeft, mMarginRight, mMarginTop, mSampleDisplay, mShowClipping, SetColours(), UpdatePrefs(), and vruler.

268 {
269  mMarginLeft = 0;
270  mMarginTop = 0;
271  mMarginRight = 0;
272  mMarginBottom = 0;
273 
275  mShowClipping = false;
276  mSampleDisplay = 1;// Stem plots by default.
277  UpdatePrefs();
278 
279  SetColours(0);
280  vruler = std::make_unique<Ruler>();
281 }
long mShowClipping
Definition: TrackArtist.h:181
std::unique_ptr< Ruler > vruler
Definition: TrackArtist.h:213
void UpdatePrefs()
#define ENV_DB_RANGE
Definition: GUISettings.h:16
int mSampleDisplay
Definition: TrackArtist.h:182
void SetColours(int iColorIndex)
float mdBrange
Definition: TrackArtist.h:180
int mMarginRight
Definition: TrackArtist.h:187
int mMarginBottom
Definition: TrackArtist.h:188
TrackArtist::~TrackArtist ( )

Definition at line 283 of file TrackArtist.cpp.

284 {
285 }

Member Function Documentation

void TrackArtist::DrawBackgroundWithSelection ( wxDC *  dc,
const wxRect &  rect,
const Track track,
wxBrush &  selBrush,
wxBrush &  unselBrush,
const SelectedRegion selectedRegion,
const ZoomInfo zoomInfo 
)
static

Definition at line 3439 of file TrackArtist.cpp.

References DrawSyncLockTiles(), Track::GetSelected(), if(), Track::IsSyncLockSelected(), SelectedRegion::t0(), SelectedRegion::t1(), ZoomInfo::TimeToPosition(), and within().

Referenced by LabelTrack::Draw(), DrawSpectrum(), and DrawWaveform().

3442 {
3443  //MM: Draw background. We should optimize that a bit more.
3444  const double sel0 = selectedRegion.t0();
3445  const double sel1 = selectedRegion.t1();
3446 
3447  dc->SetPen(*wxTRANSPARENT_PEN);
3448  if (track->GetSelected() || track->IsSyncLockSelected())
3449  {
3450  // Rectangles before, within, after the selction
3451  wxRect before = rect;
3452  wxRect within = rect;
3453  wxRect after = rect;
3454 
3455  before.width = (int)(zoomInfo.TimeToPosition(sel0) );
3456  if (before.GetRight() > rect.GetRight()) {
3457  before.width = rect.width;
3458  }
3459 
3460  if (before.width > 0) {
3461  dc->SetBrush(unselBrush);
3462  dc->DrawRectangle(before);
3463 
3464  within.x = 1 + before.GetRight();
3465  }
3466  within.width = rect.x + (int)(zoomInfo.TimeToPosition(sel1) ) - within.x -1;
3467 
3468  if (within.GetRight() > rect.GetRight()) {
3469  within.width = 1 + rect.GetRight() - within.x;
3470  }
3471 
3472  if (within.width > 0) {
3473  if (track->GetSelected()) {
3474  dc->SetBrush(selBrush);
3475  dc->DrawRectangle(within);
3476  }
3477  else {
3478  // Per condition above, track must be sync-lock selected
3479  dc->SetBrush(unselBrush);
3480  dc->DrawRectangle(within);
3481  DrawSyncLockTiles(dc, within);
3482  }
3483 
3484  after.x = 1 + within.GetRight();
3485  }
3486  else {
3487  // `within` not drawn; start where it would have gone
3488  after.x = within.x;
3489  }
3490 
3491  after.width = 1 + rect.GetRight() - after.x;
3492  if (after.width > 0) {
3493  dc->SetBrush(unselBrush);
3494  dc->DrawRectangle(after);
3495  }
3496  }
3497  else
3498  {
3499  // Track not selected; just draw background
3500  dc->SetBrush(unselBrush);
3501  dc->DrawRectangle(rect);
3502  }
3503 }
double t0() const
bool GetSelected() const
Definition: Track.h:275
bool IsSyncLockSelected() const
Definition: Track.cpp:295
double t1() const
static void DrawSyncLockTiles(wxDC *dc, wxRect rect)
wxInt64 TimeToPosition(double time, wxInt64 origin=0, bool ignoreFisheye=false) const
STM: Converts a project time to screen x position.
Definition: ViewInfo.cpp:59
if(pTrack &&pTrack->GetDisplay()!=WaveTrack::Spectrum)
bool within(A a, B b, DIST d)
Definition: TrackPanel.cpp:252
void TrackArtist::DrawClipSpectrum ( WaveTrackCache cache,
const WaveClip clip,
wxDC &  dc,
const wxRect &  rect,
const SelectedRegion selectedRegion,
const ZoomInfo zoomInfo 
)
private

Definition at line 2202 of file TrackArtist.cpp.

References SpectrogramSettings::algorithm, SpectrogramSettings::algPitchEAC, ChooseColorSet(), AColor::ColorGradientUnselected, SelectedRegion::f0(), SelectedRegion::f1(), SpectrogramSettings::findBin(), findValue(), SpecCache::freq, SpectrogramSettings::gain, GetColorGradient(), SpectrogramSettings::GetFFTLength(), ZoomInfo::GetFisheyeLeftBoundary(), ZoomInfo::GetFisheyeRightBoundary(), ZoomInfo::GetFisheyeState(), WaveClip::GetNumSamples(), SpectrogramSettings::GetScale(), WaveClip::GetSpectrogram(), WaveTrack::GetSpectrogramSettings(), WaveTrack::GetSpectrumBounds(), WaveTrackCache::GetTrack(), AColor::gradient_inited, SpecCache::Grow(), ZoomInfo::HIDDEN, ZoomInfo::InFisheye(), SpectrogramSettings::isGrayscale, min(), WaveClip::mSpecPxCache, SpectrogramSettings::NBins(), params, SpecCache::Populate(), ZoomInfo::PositionToTime(), AColor::PreComputeGradient(), SpectrogramSettings::range, SpectrogramSettings::scaleType, WaveClip::SetDisplayRect(), SpectrogramSettings::SpectralSelectionEnabled(), SpectrogramSettings::stLogarithmic, SelectedRegion::UndefinedFrequency, and SpecCache::where.

Referenced by DrawSpectrum().

2208 {
2209 #ifdef PROFILE_WAVEFORM
2210  Profiler profiler;
2211 #endif
2212 
2213  const WaveTrack *const track = waveTrackCache.GetTrack();
2214  const SpectrogramSettings &settings = track->GetSpectrogramSettings();
2215  const bool autocorrelation = (settings.algorithm == SpectrogramSettings::algPitchEAC);
2216 
2217  enum { DASH_LENGTH = 10 /* pixels */ };
2218 
2219  const ClipParameters params(true, track, clip, rect, selectedRegion, zoomInfo);
2220  const wxRect &hiddenMid = params.hiddenMid;
2221  // The "hiddenMid" rect contains the part of the display actually
2222  // containing the waveform, as it appears without the fisheye. If it's empty, we're done.
2223  if (hiddenMid.width <= 0) {
2224  return;
2225  }
2226 
2227  const double &t0 = params.t0;
2228  const double &tOffset = params.tOffset;
2229  const auto &ssel0 = params.ssel0;
2230  const auto &ssel1 = params.ssel1;
2231  const double &averagePixelsPerSample = params.averagePixelsPerSample;
2232  const double &rate = params.rate;
2233  const double &hiddenLeftOffset = params.hiddenLeftOffset;
2234  const double &leftOffset = params.leftOffset;
2235  const wxRect &mid = params.mid;
2236 
2237  // If we get to this point, the clip is actually visible on the
2238  // screen, so remember the display rectangle.
2239  clip->SetDisplayRect(hiddenMid);
2240 
2241  double freqLo = SelectedRegion::UndefinedFrequency;
2242  double freqHi = SelectedRegion::UndefinedFrequency;
2243 #ifdef EXPERIMENTAL_SPECTRAL_EDITING
2244  freqLo = selectedRegion.f0();
2245  freqHi = selectedRegion.f1();
2246 #endif
2247 
2248  const bool &isGrayscale = settings.isGrayscale;
2249  const int &range = settings.range;
2250  const int &gain = settings.gain;
2251 
2252 #ifdef EXPERIMENTAL_FIND_NOTES
2253  const bool &fftFindNotes = settings.fftFindNotes;
2254  const double &findNotesMinA = settings.findNotesMinA;
2255  const int &numberOfMaxima = settings.numberOfMaxima;
2256  const bool &findNotesQuantize = settings.findNotesQuantize;
2257 #endif
2258 #ifdef EXPERIMENTAL_FFT_Y_GRID
2259  const bool &fftYGrid = settings.fftYGrid;
2260 #endif
2261 
2262  dc.SetPen(*wxTRANSPARENT_PEN);
2263 
2264  // We draw directly to a bit image in memory,
2265  // and then paint this directly to our offscreen
2266  // bitmap. Note that this could be optimized even
2267  // more, but for now this is not bad. -dmazzoni
2268  wxImage image((int)mid.width, (int)mid.height);
2269  if (!image.IsOk())
2270  return;
2271 #ifdef EXPERIMENTAL_SPECTROGRAM_OVERLAY
2272  image.SetAlpha();
2273  unsigned char *alpha = image.GetAlpha();
2274 #endif
2275  unsigned char *data = image.GetData();
2276 
2277  const auto half = settings.GetFFTLength() / 2;
2278  const double binUnit = rate / (2 * half);
2279  const float *freq = 0;
2280  const sampleCount *where = 0;
2281  bool updated;
2282  {
2283  const double pps = averagePixelsPerSample * rate;
2284  updated = clip->GetSpectrogram(waveTrackCache, freq, where,
2285  (size_t)hiddenMid.width,
2286  t0, pps);
2287  }
2288  auto nBins = settings.NBins();
2289 
2290  float minFreq, maxFreq;
2291  track->GetSpectrumBounds(&minFreq, &maxFreq);
2292 
2293  const SpectrogramSettings::ScaleType scaleType = settings.scaleType;
2294 
2295  // nearest frequency to each pixel row from number scale, for selecting
2296  // the desired fft bin(s) for display on that row
2297  float *bins = (float*)alloca(sizeof(*bins)*(hiddenMid.height + 1));
2298  {
2299  const NumberScale numberScale( settings.GetScale( minFreq, maxFreq ) );
2300 
2301  NumberScale::Iterator it = numberScale.begin(mid.height);
2302  float nextBin = std::max( 0.0f, std::min( float(nBins - 1),
2303  settings.findBin( *it, binUnit ) ) );
2304 
2305  int yy;
2306  for (yy = 0; yy < hiddenMid.height; ++yy) {
2307  bins[yy] = nextBin;
2308  nextBin = std::max( 0.0f, std::min( float(nBins - 1),
2309  settings.findBin( *++it, binUnit ) ) );
2310  }
2311  bins[yy] = nextBin;
2312  }
2313 
2314 #ifdef EXPERIMENTAL_FFT_Y_GRID
2315  const float
2316  log2 = logf(2.0f),
2317  scale2 = (lmax - lmin) / log2,
2318  lmin2 = lmin / log2;
2319 
2320  ArrayOf<bool> yGrid{size_t(mid.height)};
2321  for (int yy = 0; yy < mid.height; ++yy) {
2322  float n = (float(yy) / mid.height*scale2 - lmin2) * 12;
2323  float n2 = (float(yy + 1) / mid.height*scale2 - lmin2) * 12;
2324  float f = float(minFreq) / (fftSkipPoints + 1)*powf(2.0f, n / 12.0f + lmin2);
2325  float f2 = float(minFreq) / (fftSkipPoints + 1)*powf(2.0f, n2 / 12.0f + lmin2);
2326  n = logf(f / 440) / log2 * 12;
2327  n2 = logf(f2 / 440) / log2 * 12;
2328  if (floor(n) < floor(n2))
2329  yGrid[yy] = true;
2330  else
2331  yGrid[yy] = false;
2332  }
2333 #endif //EXPERIMENTAL_FFT_Y_GRID
2334 
2335  if (!updated && clip->mSpecPxCache->valid &&
2336  ((int)clip->mSpecPxCache->len == hiddenMid.height * hiddenMid.width)
2337  && scaleType == clip->mSpecPxCache->scaleType
2338  && gain == clip->mSpecPxCache->gain
2339  && range == clip->mSpecPxCache->range
2340  && minFreq == clip->mSpecPxCache->minFreq
2341  && maxFreq == clip->mSpecPxCache->maxFreq
2342 #ifdef EXPERIMENTAL_FFT_Y_GRID
2343  && fftYGrid==fftYGridOld
2344 #endif //EXPERIMENTAL_FFT_Y_GRID
2345 #ifdef EXPERIMENTAL_FIND_NOTES
2346  && fftFindNotes==fftFindNotesOld
2347  && findNotesMinA==findNotesMinAOld
2348  && numberOfMaxima==findNotesNOld
2349  && findNotesQuantize==findNotesQuantizeOld
2350 #endif
2351  ) {
2352  // Wave clip's spectrum cache is up to date,
2353  // and so is the spectrum pixel cache
2354  }
2355  else {
2356  // Update the spectrum pixel cache
2357  clip->mSpecPxCache = std::make_unique<SpecPxCache>(hiddenMid.width * hiddenMid.height);
2358  clip->mSpecPxCache->valid = true;
2359  clip->mSpecPxCache->scaleType = scaleType;
2360  clip->mSpecPxCache->gain = gain;
2361  clip->mSpecPxCache->range = range;
2362  clip->mSpecPxCache->minFreq = minFreq;
2363  clip->mSpecPxCache->maxFreq = maxFreq;
2364 #ifdef EXPERIMENTAL_FIND_NOTES
2365  fftFindNotesOld = fftFindNotes;
2366  findNotesMinAOld = findNotesMinA;
2367  findNotesNOld = numberOfMaxima;
2368  findNotesQuantizeOld = findNotesQuantize;
2369 #endif
2370 
2371 #ifdef EXPERIMENTAL_FIND_NOTES
2372  float log2 = logf( 2.0f ),
2373  lmin = logf( minFreq ), lmax = logf( maxFreq ), scale = lmax - lmin,
2374  lmins = lmin,
2375  lmaxs = lmax
2376  ;
2377 #endif //EXPERIMENTAL_FIND_NOTES
2378 
2379 #ifdef EXPERIMENTAL_FIND_NOTES
2380  int maxima[128];
2381  float maxima0[128], maxima1[128];
2382  const float
2383  f2bin = half / (rate / 2.0f),
2384  bin2f = 1.0f / f2bin,
2385  minDistance = powf(2.0f, 2.0f / 12.0f),
2386  i0 = expf(lmin) / binUnit,
2387  i1 = expf(scale + lmin) / binUnit,
2388  minColor = 0.0f;
2389  const size_t maxTableSize = 1024;
2390  ArrayOf<int> indexes{ maxTableSize };
2391 #endif //EXPERIMENTAL_FIND_NOTES
2392 
2393 #ifdef _OPENMP
2394 #pragma omp parallel for
2395 #endif
2396  for (int xx = 0; xx < hiddenMid.width; ++xx) {
2397 #ifdef EXPERIMENTAL_FIND_NOTES
2398  int maximas = 0;
2399  const int x0 = nBins * xx;
2400  if (fftFindNotes) {
2401  for (int i = maxTableSize - 1; i >= 0; i--)
2402  indexes[i] = -1;
2403 
2404  // Build a table of (most) values, put the index in it.
2405  for (int i = (int)(i0); i < (int)(i1); i++) {
2406  float freqi = freq[x0 + (int)(i)];
2407  int value = (int)((freqi + gain + range) / range*(maxTableSize - 1));
2408  if (value < 0)
2409  value = 0;
2410  if (value >= maxTableSize)
2411  value = maxTableSize - 1;
2412  indexes[value] = i;
2413  }
2414  // Build from the indices an array of maxima.
2415  for (int i = maxTableSize - 1; i >= 0; i--) {
2416  int index = indexes[i];
2417  if (index >= 0) {
2418  float freqi = freq[x0 + index];
2419  if (freqi < findNotesMinA)
2420  break;
2421 
2422  bool ok = true;
2423  for (int m = 0; m < maximas; m++) {
2424  // Avoid to store very close maxima.
2425  float maxm = maxima[m];
2426  if (maxm / index < minDistance && index / maxm < minDistance) {
2427  ok = false;
2428  break;
2429  }
2430  }
2431  if (ok) {
2432  maxima[maximas++] = index;
2433  if (maximas >= numberOfMaxima)
2434  break;
2435  }
2436  }
2437  }
2438 
2439 // The f2pix helper macro converts a frequency into a pixel coordinate.
2440 #define f2pix(f) (logf(f)-lmins)/(lmaxs-lmins)*hiddenMid.height
2441 
2442  // Possibly quantize the maxima frequencies and create the pixel block limits.
2443  for (int i = 0; i < maximas; i++) {
2444  int index = maxima[i];
2445  float f = float(index)*bin2f;
2446  if (findNotesQuantize)
2447  {
2448  f = expf((int)(log(f / 440) / log2 * 12 - 0.5) / 12.0f*log2) * 440;
2449  maxima[i] = f*f2bin;
2450  }
2451  float f0 = expf((log(f / 440) / log2 * 24 - 1) / 24.0f*log2) * 440;
2452  maxima0[i] = f2pix(f0);
2453  float f1 = expf((log(f / 440) / log2 * 24 + 1) / 24.0f*log2) * 440;
2454  maxima1[i] = f2pix(f1);
2455  }
2456  }
2457 
2458  int it = 0;
2459  bool inMaximum = false;
2460 #endif //EXPERIMENTAL_FIND_NOTES
2461 
2462  for (int yy = 0; yy < hiddenMid.height; ++yy) {
2463  const float bin = bins[yy];
2464  const float nextBin = bins[yy+1];
2465 
2467  const float value = findValue
2468  (freq + nBins * xx, bin, nextBin, nBins, autocorrelation, gain, range);
2469  clip->mSpecPxCache->values[xx * hiddenMid.height + yy] = value;
2470  }
2471  else {
2472  float value;
2473 
2474 #ifdef EXPERIMENTAL_FIND_NOTES
2475  if (fftFindNotes) {
2476  if (it < maximas) {
2477  float i0 = maxima0[it];
2478  if (yy >= i0)
2479  inMaximum = true;
2480 
2481  if (inMaximum) {
2482  float i1 = maxima1[it];
2483  if (yy + 1 <= i1) {
2484  value = findValue(freq + x0, bin, nextBin, nBins, autocorrelation, gain, range);
2485  if (value < findNotesMinA)
2486  value = minColor;
2487  }
2488  else {
2489  it++;
2490  inMaximum = false;
2491  value = minColor;
2492  }
2493  }
2494  else {
2495  value = minColor;
2496  }
2497  }
2498  else
2499  value = minColor;
2500  }
2501  else
2502 #endif //EXPERIMENTAL_FIND_NOTES
2503  {
2504  value = findValue
2505  (freq + nBins * xx, bin, nextBin, nBins, autocorrelation, gain, range);
2506  }
2507  clip->mSpecPxCache->values[xx * hiddenMid.height + yy] = value;
2508  } // logF
2509  } // each yy
2510  } // each xx
2511  } // updating cache
2512 
2513  float selBinLo = settings.findBin( freqLo, binUnit);
2514  float selBinHi = settings.findBin( freqHi, binUnit);
2515  float selBinCenter = (freqLo < 0 || freqHi < 0)
2516  ? -1
2517  : settings.findBin( sqrt(freqLo * freqHi), binUnit );
2518 
2519  const bool isSpectral = settings.SpectralSelectionEnabled();
2520  const bool hidden = (ZoomInfo::HIDDEN == zoomInfo.GetFisheyeState());
2521  const int begin = hidden
2522  ? 0
2523  : std::max(0, (int)(zoomInfo.GetFisheyeLeftBoundary(-leftOffset)));
2524  const int end = hidden
2525  ? 0
2526  : std::min(mid.width, (int)(zoomInfo.GetFisheyeRightBoundary(-leftOffset)));
2527  const size_t numPixels = std::max(0, end - begin);
2528 
2529  SpecCache specCache;
2530 
2531  // need explicit resize since specCache.where[] accessed before Populate()
2532  specCache.Grow(numPixels, settings, -1, t0);
2533 
2534  if (numPixels > 0) {
2535  for (int ii = begin; ii < end; ++ii) {
2536  const double time = zoomInfo.PositionToTime(ii, -leftOffset) - tOffset;
2537  specCache.where[ii - begin] = sampleCount(0.5 + rate * time);
2538  }
2539  specCache.Populate
2540  (settings, waveTrackCache,
2541  0, 0, numPixels,
2542  clip->GetNumSamples(),
2543  tOffset, rate,
2544  0 // FIXME: PRL -- make reassignment work with fisheye
2545  );
2546  }
2547 
2548  // build color gradient tables (not thread safe)
2551 
2552  // left pixel column of the fisheye
2553  int fisheyeLeft = zoomInfo.GetFisheyeLeftBoundary(-leftOffset);
2554 
2555 #ifdef _OPENMP
2556 #pragma omp parallel for
2557 #endif
2558  for (int xx = 0; xx < mid.width; ++xx) {
2559 
2560  int correctedX = xx + leftOffset - hiddenLeftOffset;
2561 
2562  // in fisheye mode the time scale has changed, so the row values aren't cached
2563  // in the loop above, and must be fetched from fft cache
2564  float* uncached;
2565  if (!zoomInfo.InFisheye(xx, -leftOffset)) {
2566  uncached = 0;
2567  }
2568  else {
2569  int specIndex = (xx - fisheyeLeft) * nBins;
2570  wxASSERT(specIndex >= 0 && specIndex < (int)specCache.freq.size());
2571  uncached = &specCache.freq[specIndex];
2572  }
2573 
2574  // zoomInfo must be queried for each column since with fisheye enabled
2575  // time between columns is variable
2576  auto w0 = sampleCount(0.5 + rate *
2577  (zoomInfo.PositionToTime(xx, -leftOffset) - tOffset));
2578 
2579  auto w1 = sampleCount(0.5 + rate *
2580  (zoomInfo.PositionToTime(xx+1, -leftOffset) - tOffset));
2581 
2582  bool maybeSelected = ssel0 <= w0 && w1 < ssel1;
2583 
2584  for (int yy = 0; yy < hiddenMid.height; ++yy) {
2585  const float bin = bins[yy];
2586  const float nextBin = bins[yy+1];
2587 
2588  // For spectral selection, determine what colour
2589  // set to use. We use a darker selection if
2590  // in both spectral range and time range.
2591 
2593 
2594  // If we are in the time selected range, then we may use a different color set.
2595  if (maybeSelected)
2596  selected =
2597  ChooseColorSet(bin, nextBin, selBinLo, selBinCenter, selBinHi,
2598  (xx + leftOffset - hiddenLeftOffset) / DASH_LENGTH, isSpectral);
2599 
2600  const float value = uncached
2601  ? findValue(uncached, bin, nextBin, nBins, autocorrelation, gain, range)
2602  : clip->mSpecPxCache->values[correctedX * hiddenMid.height + yy];
2603 
2604  unsigned char rv, gv, bv;
2605  GetColorGradient(value, selected, isGrayscale, &rv, &gv, &bv);
2606 
2607 #ifdef EXPERIMENTAL_FFT_Y_GRID
2608  if (fftYGrid && yGrid[yy]) {
2609  rv /= 1.1f;
2610  gv /= 1.1f;
2611  bv /= 1.1f;
2612  }
2613 #endif //EXPERIMENTAL_FFT_Y_GRID
2614 
2615  int px = ((mid.height - 1 - yy) * mid.width + xx);
2616 #ifdef EXPERIMENTAL_SPECTROGRAM_OVERLAY
2617  // More transparent the closer to zero intensity.
2618  alpha[px]= wxMin( 200, (value+0.3) * 500) ;
2619 #endif
2620  px *=3;
2621  data[px++] = rv;
2622  data[px++] = gv;
2623  data[px] = bv;
2624  } // each yy
2625  } // each xx
2626 
2627  wxBitmap converted = wxBitmap(image);
2628 
2629  wxMemoryDC memDC;
2630 
2631  memDC.SelectObject(converted);
2632 
2633  dc.Blit(mid.x, mid.y, mid.width, mid.height, &memDC, 0, 0, wxCOPY, FALSE);
2634 }
static float findValue(const float *spectrum, float bin0, float bin1, unsigned nBins, bool autocorrelation, int gain, int range)
ColorGradientChoice
Definition: AColor.h:53
Spectrogram settings, either for one track or as defaults.
sampleCount GetNumSamples() const
Definition: WaveClip.cpp:448
std::unique_ptr< SpecPxCache > mSpecPxCache
Definition: WaveClip.h:369
void GetColorGradient(float value, AColor::ColorGradientChoice selected, bool grayscale, unsigned char *__restrict red, unsigned char *__restrict green, unsigned char *__restrict blue)
Definition: AColor.h:157
A simple profiler to measure the average time lengths that a particular task/function takes...
Definition: Profiler.h:39
void GetSpectrumBounds(float *min, float *max) const
Definition: WaveTrack.cpp:337
wxInt64 GetFisheyeLeftBoundary(wxInt64 WXUNUSED(origin=0)) const
Definition: ViewInfo.h:134
bool SpectralSelectionEnabled() const
double PositionToTime(wxInt64 position, wxInt64 origin=0, bool ignoreFisheye=false) const
Definition: ViewInfo.cpp:49
size_t GetFFTLength() const
const SpectrogramSettings & GetSpectrogramSettings() const
Definition: WaveTrack.cpp:690
bool InFisheye(wxInt64, wxInt64 WXUNUSED(origin=0)) const
Definition: ViewInfo.h:129
NumberScale GetScale(float minFreq, float maxFreq) const
double f0() const
void Grow(size_t len_, const SpectrogramSettings &settings, double pixelsPerSecond, double start_)
Definition: WaveClip.cpp:1045
FisheyeState GetFisheyeState() const
Definition: ViewInfo.h:124
float findBin(float frequency, float binUnit) const
A Track that contains audio waveform data.
Definition: WaveTrack.h:60
static void PreComputeGradient()
Definition: AColor.cpp:624
int min(int a, int b)
wxInt64 GetFisheyeRightBoundary(wxInt64 WXUNUSED(origin=0)) const
Definition: ViewInfo.h:137
bool GetSpectrogram(WaveTrackCache &cache, const float *&spectrogram, const sampleCount *&where, size_t numPixels, double t0, double pixelsPerSecond) const
Definition: WaveClip.cpp:1197
void SetDisplayRect(const wxRect &r) const
Definition: WaveClip.cpp:1383
AColor::ColorGradientChoice ChooseColorSet(float bin0, float bin1, float selBinLo, float selBinCenter, float selBinHi, int dashCount, bool isSpectral)
double f1() const
static bool gradient_inited
Definition: AColor.h:142
EffectDistortion::Params params
Definition: Distortion.cpp:95
static const int UndefinedFrequency
void Populate(const SpectrogramSettings &settings, WaveTrackCache &waveTrackCache, int copyBegin, int copyEnd, size_t numPixels, sampleCount numSamples, double offset, double rate, double pixelsPerSecond)
Definition: WaveClip.cpp:1069
std::vector< float > freq
Definition: WaveClip.h:89
std::vector< sampleCount > where
Definition: WaveClip.h:90
void TrackArtist::DrawClipWaveform ( TrackPanelDrawingContext context,
const WaveTrack track,
const WaveClip clip,
const wxRect &  rect,
const SelectedRegion selectedRegion,
const ZoomInfo zoomInfo,
bool  drawEnvelope,
bool  bigPoints,
bool  dB,
bool  muted 
)
private

Definition at line 1797 of file TrackArtist.cpp.

References WaveDisplay::Allocate(), WaveDisplay::bl, WaveformSettings::dBRange, TrackPanelDrawingContext::dc, DrawEnvelope(), DrawIndividualSamples(), DrawMinMaxRMS(), DrawNegativeOffsetTrackArrows(), Envelope::DrawPoints(), DrawWaveformBackground(), WaveClip::GetColourIndex(), WaveTrack::GetDisplayBounds(), EnvelopeHandle::GetEnvelope(), WaveClip::GetEnvelope(), WaveClip::GetNumSamples(), Track::GetSelected(), SampleHandle::GetTrack(), Envelope::GetValues(), WaveClip::GetWaveDisplay(), WaveTrack::GetWaveformSettings(), Track::IsSyncLockSelected(), AColor::Line(), WaveTrack::LongSamplesToTime(), WaveDisplay::max, WaveDisplay::min, params, ZoomInfo::PositionToTime(), WaveDisplay::rms, SetColours(), WaveClip::SetDisplayRect(), SelectedRegion::t0(), SelectedRegion::t1(), TrackPanelDrawingContext::target, WaveTrack::TimeToLongSamples(), WaveDisplay::where, WaveDisplay::width, and WaveTrack::ZeroLevelYCoordinate().

Referenced by DrawWaveform().

1807 {
1808  auto &dc = context.dc;
1809 #ifdef PROFILE_WAVEFORM
1810  Profiler profiler;
1811 #endif
1812 
1813  bool highlightEnvelope = false;
1814 #ifdef EXPERIMENTAL_TRACK_PANEL_HIGHLIGHTING
1815  auto target = dynamic_cast<EnvelopeHandle*>(context.target.get());
1816  highlightEnvelope = target && target->GetEnvelope() == clip->GetEnvelope();
1817 #endif
1818 
1819  const ClipParameters params(false, track, clip, rect, selectedRegion, zoomInfo);
1820  const wxRect &hiddenMid = params.hiddenMid;
1821  // The "hiddenMid" rect contains the part of the display actually
1822  // containing the waveform, as it appears without the fisheye. If it's empty, we're done.
1823  if (hiddenMid.width <= 0) {
1824  return;
1825  }
1826 
1827  const double &t0 = params.t0;
1828  const double &tOffset = params.tOffset;
1829  const double &h = params.h;
1830  const double &tpre = params.tpre;
1831  const double &tpost = params.tpost;
1832  const double &t1 = params.t1;
1833  const double &averagePixelsPerSample = params.averagePixelsPerSample;
1834  const double &rate = params.rate;
1835  double leftOffset = params.leftOffset;
1836  const wxRect &mid = params.mid;
1837 
1838  const float dBRange = track->GetWaveformSettings().dBRange;
1839 
1840  dc.SetPen(*wxTRANSPARENT_PEN);
1841  int iColorIndex = clip->GetColourIndex();
1842  SetColours( iColorIndex );
1843 
1844  // If we get to this point, the clip is actually visible on the
1845  // screen, so remember the display rectangle.
1846  clip->SetDisplayRect(hiddenMid);
1847 
1848  // The bounds (controlled by vertical zooming; -1.0...1.0
1849  // by default)
1850  float zoomMin, zoomMax;
1851  track->GetDisplayBounds(&zoomMin, &zoomMax);
1852 
1853  std::vector<double> vEnv(mid.width);
1854  double *const env = &vEnv[0];
1855  clip->GetEnvelope()->GetValues
1856  ( tOffset,
1857 
1858  // PRL: change back to make envelope evaluate only at sample times
1859  // and then interpolate the display
1860  0, // 1.0 / rate,
1861 
1862  env, mid.width, leftOffset, zoomInfo );
1863 
1864  // Draw the background of the track, outlining the shape of
1865  // the envelope and using a colored pen for the selected
1866  // part of the waveform
1867  {
1868  double t0, t1;
1869  if (track->GetSelected() || track->IsSyncLockSelected()) {
1870  t0 = track->LongSamplesToTime(track->TimeToLongSamples(selectedRegion.t0())),
1871  t1 = track->LongSamplesToTime(track->TimeToLongSamples(selectedRegion.t1()));
1872  }
1873  else
1874  t0 = t1 = 0.0;
1875  DrawWaveformBackground(dc, leftOffset, mid,
1876  env,
1877  zoomMin, zoomMax,
1878  track->ZeroLevelYCoordinate(mid),
1879  dB, dBRange,
1880  t0, t1, zoomInfo, drawEnvelope,
1881  !track->GetSelected(), highlightEnvelope);
1882  }
1883 
1884  WaveDisplay display(hiddenMid.width);
1885  bool isLoadingOD = false;//true if loading on demand block in sequence.
1886 
1887  const double pps =
1888  averagePixelsPerSample * rate;
1889 
1890  // For each portion separately, we will decide to draw
1891  // it as min/max/rms or as individual samples.
1892  std::vector<WavePortion> portions;
1893  FindWavePortions(portions, rect, zoomInfo, params);
1894  const unsigned nPortions = portions.size();
1895 
1896  // Require at least 1/2 pixel per sample for drawing individual samples.
1897  const double threshold1 = 0.5 * rate;
1898  // Require at least 3 pixels per sample for drawing the draggable points.
1899  const double threshold2 = 3 * rate;
1900 
1901  {
1902  bool showIndividualSamples = false;
1903  for (unsigned ii = 0; !showIndividualSamples && ii < nPortions; ++ii) {
1904  const WavePortion &portion = portions[ii];
1905  showIndividualSamples =
1906  !portion.inFisheye && portion.averageZoom > threshold1;
1907  }
1908 
1909  if (!showIndividualSamples) {
1910  // The WaveClip class handles the details of computing the shape
1911  // of the waveform. The only way GetWaveDisplay will fail is if
1912  // there's a serious error, like some of the waveform data can't
1913  // be loaded. So if the function returns false, we can just exit.
1914 
1915  // Note that we compute the full width display even if there is a
1916  // fisheye hiding part of it, because of the caching. If the
1917  // fisheye moves over the background, there is then less to do when
1918  // redrawing.
1919 
1920  if (!clip->GetWaveDisplay(display,
1921  t0, pps, isLoadingOD))
1922  return;
1923  }
1924  }
1925 
1926  for (unsigned ii = 0; ii < nPortions; ++ii) {
1927  WavePortion &portion = portions[ii];
1928  const bool showIndividualSamples = portion.averageZoom > threshold1;
1929  const bool showPoints = portion.averageZoom > threshold2;
1930  wxRect& rect = portion.rect;
1931  rect.Intersect(mid);
1932  wxASSERT(rect.width >= 0);
1933 
1934  float *useMin = 0, *useMax = 0, *useRms = 0;
1935  int *useBl = 0;
1936  WaveDisplay fisheyeDisplay(rect.width);
1937  int skipped = 0, skippedLeft = 0, skippedRight = 0;
1938  if (portion.inFisheye) {
1939  if (!showIndividualSamples) {
1940  fisheyeDisplay.Allocate();
1941  const auto numSamples = clip->GetNumSamples();
1942  // Get wave display data for different magnification
1943  int jj = 0;
1944  for (; jj < rect.width; ++jj) {
1945  const double time =
1946  zoomInfo.PositionToTime(jj, -leftOffset) - tOffset;
1947  const auto sample = (sampleCount)floor(time * rate + 0.5);
1948  if (sample < 0) {
1949  ++rect.x;
1950  ++skippedLeft;
1951  continue;
1952  }
1953  if (sample >= numSamples)
1954  break;
1955  fisheyeDisplay.where[jj - skippedLeft] = sample;
1956  }
1957 
1958  skippedRight = rect.width - jj;
1959  skipped = skippedRight + skippedLeft;
1960  rect.width -= skipped;
1961 
1962  // where needs a sentinel
1963  if (jj > 0)
1964  fisheyeDisplay.where[jj - skippedLeft] =
1965  1 + fisheyeDisplay.where[jj - skippedLeft - 1];
1966  fisheyeDisplay.width -= skipped;
1967  // Get a wave display for the fisheye, uncached.
1968  if (rect.width > 0)
1969  if (!clip->GetWaveDisplay(
1970  fisheyeDisplay, t0, -1.0, // ignored
1971  isLoadingOD))
1972  continue; // serious error. just don't draw??
1973  useMin = fisheyeDisplay.min;
1974  useMax = fisheyeDisplay.max;
1975  useRms = fisheyeDisplay.rms;
1976  useBl = fisheyeDisplay.bl;
1977  }
1978  }
1979  else {
1980  const int pos = leftOffset - params.hiddenLeftOffset;
1981  useMin = display.min + pos;
1982  useMax = display.max + pos;
1983  useRms = display.rms + pos;
1984  useBl = display.bl + pos;
1985  }
1986 
1987  leftOffset += skippedLeft;
1988 
1989  if (rect.width > 0) {
1990  if (!showIndividualSamples) {
1991  std::vector<double> vEnv2(rect.width);
1992  double *const env2 = &vEnv2[0];
1993  clip->GetEnvelope()->GetValues
1994  ( tOffset,
1995 
1996  // PRL: change back to make envelope evaluate only at sample times
1997  // and then interpolate the display
1998  0, // 1.0 / rate,
1999 
2000  env2, rect.width, leftOffset, zoomInfo );
2001  DrawMinMaxRMS(dc, rect, env2,
2002  zoomMin, zoomMax,
2003  dB, dBRange,
2004  useMin, useMax, useRms, useBl,
2005  isLoadingOD, muted);
2006  }
2007  else {
2008  bool highlight = false;
2009 #ifdef EXPERIMENTAL_TRACK_PANEL_HIGHLIGHTING
2010  auto target = dynamic_cast<SampleHandle*>(context.target.get());
2011  highlight = target && target->GetTrack().get() == track;
2012 #endif
2013  DrawIndividualSamples(dc, leftOffset, rect, zoomMin, zoomMax,
2014  dB, dBRange,
2015  clip, zoomInfo,
2016  bigPoints, showPoints, muted, highlight);
2017  }
2018  }
2019 
2020  leftOffset += rect.width + skippedRight;
2021  }
2022 
2023  if (drawEnvelope) {
2024  DrawEnvelope(dc, mid, env, zoomMin, zoomMax, dB, dBRange, highlightEnvelope);
2025  clip->GetEnvelope()->DrawPoints
2026  (context, rect, zoomInfo, dB, dBRange, zoomMin, zoomMax, true);
2027  }
2028 
2029  // Draw arrows on the left side if the track extends to the left of the
2030  // beginning of time. :)
2031  if (h == 0.0 && tOffset < 0.0) {
2033  }
2034 
2035  // Draw clip edges
2036  dc.SetPen(*wxGREY_PEN);
2037  if (tpre < 0) {
2038  AColor::Line(dc,
2039  mid.x - 1, mid.y,
2040  mid.x - 1, mid.y + rect.height);
2041  }
2042  if (tpost > t1) {
2043  AColor::Line(dc,
2044  mid.x + mid.width, mid.y,
2045  mid.x + mid.width, mid.y + rect.height);
2046  }
2047 }
void DrawPoints(TrackPanelDrawingContext &context, const wxRect &r, const ZoomInfo &zoomInfo, bool dB, double dBRange, float zoomMin, float zoomMax, bool mirrored) const
TODO: This should probably move to track artist.
Definition: Envelope.cpp:322
double t0() const
int ZeroLevelYCoordinate(wxRect rect) const
Definition: WaveTrack.cpp:387
sampleCount GetNumSamples() const
Definition: WaveClip.cpp:448
void DrawNegativeOffsetTrackArrows(wxDC &dc, const wxRect &rect)
bool GetSelected() const
Definition: Track.h:275
void DrawIndividualSamples(wxDC &dc, int leftOffset, const wxRect &rect, float zoomMin, float zoomMax, bool dB, float dBRange, const WaveClip *clip, const ZoomInfo &zoomInfo, bool bigPoints, bool showPoints, bool muted, bool highlight)
const WaveformSettings & GetWaveformSettings() const
Definition: WaveTrack.cpp:738
A simple profiler to measure the average time lengths that a particular task/function takes...
Definition: Profiler.h:39
bool IsSyncLockSelected() const
Definition: Track.cpp:295
double t1() const
Envelope * GetEnvelope()
Definition: WaveClip.h:243
void DrawWaveformBackground(wxDC &dc, int leftOffset, const wxRect &rect, const double env[], float zoomMin, float zoomMax, int zeroLevelYCoordinate, bool dB, float dBRange, double t0, double t1, const ZoomInfo &zoomInfo, bool drawEnvelope, bool bIsSyncLockSelected, bool highlightEnvelope)
void GetDisplayBounds(float *min, float *max) const
Definition: WaveTrack.cpp:325
bool GetWaveDisplay(WaveDisplay &display, double t0, double pixelsPerSecond, bool &isLoadingOD) const
Definition: WaveClip.cpp:550
void SetColours(int iColorIndex)
std::shared_ptr< WaveTrack > GetTrack() const
Definition: SampleHandle.h:47
static void Line(wxDC &dc, wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2)
Definition: AColor.cpp:122
void DrawEnvelope(wxDC &dc, const wxRect &rect, const double env[], float zoomMin, float zoomMax, bool dB, float dBRange, bool highlight)
int GetColourIndex() const
Definition: WaveClip.h:220
void SetDisplayRect(const wxRect &r) const
Definition: WaveClip.cpp:1383
sampleCount TimeToLongSamples(double t0) const
Convert correctly between an (absolute) time in seconds and a number of samples.
Definition: WaveTrack.cpp:1843
Envelope * GetEnvelope() const
void DrawMinMaxRMS(wxDC &dc, 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, bool muted)
void GetValues(double *buffer, int len, double t0, double tstep) const
Get many envelope points at once.
Definition: Envelope.cpp:1214
double LongSamplesToTime(sampleCount pos) const
Convert correctly between an number of samples and an (absolute) time in seconds. ...
Definition: WaveTrack.cpp:1848
EffectDistortion::Params params
Definition: Distortion.cpp:95
void TrackArtist::DrawEnvelope ( wxDC &  dc,
const wxRect &  rect,
const double  env[],
float  zoomMin,
float  zoomMax,
bool  dB,
float  dBRange,
bool  highlight 
)
private

Definition at line 1449 of file TrackArtist.cpp.

References DrawEnvLine(), AColor::envelopePen, GetWaveYPos(), and AColor::uglyPen.

Referenced by DrawClipWaveform().

1452 {
1453  int h = rect.height;
1454 
1455  auto &pen = highlight ? AColor::uglyPen : AColor::envelopePen;
1456  dc.SetPen( pen );
1457 
1458  for (int x0 = 0; x0 < rect.width; ++x0) {
1459  int cenvTop = GetWaveYPos(env[x0], zoomMin, zoomMax,
1460  h, dB, true, dBRange, true);
1461 
1462  int cenvBot = GetWaveYPos(-env[x0], zoomMin, zoomMax,
1463  h, dB, true, dBRange, true);
1464 
1465  int envTop = GetWaveYPos(env[x0], zoomMin, zoomMax,
1466  h, dB, true, dBRange, false);
1467 
1468  int envBot = GetWaveYPos(-env[x0], zoomMin, zoomMax,
1469  h, dB, true, dBRange, false);
1470 
1471  // Make the collision at zero actually look solid
1472  if (cenvBot - cenvTop < 9) {
1473  int value = (int)((zoomMax / (zoomMax - zoomMin)) * h);
1474  cenvTop = value - 4;
1475  cenvBot = value + 4;
1476  }
1477 
1478  DrawEnvLine(dc, rect, x0, envTop, cenvTop, true);
1479  DrawEnvLine(dc, rect, x0, envBot, cenvBot, false);
1480  }
1481 }
void DrawEnvLine(wxDC &dc, const wxRect &rect, int x0, int y0, int cy, bool top)
static wxPen uglyPen
Definition: AColor.h:147
static wxPen envelopePen
Definition: AColor.h:122
int GetWaveYPos(float value, float min, float max, int height, bool dB, bool outer, float dBr, bool clip)
void TrackArtist::DrawEnvLine ( wxDC &  dc,
const wxRect &  rect,
int  x0,
int  y0,
int  cy,
bool  top 
)
private

Definition at line 1483 of file TrackArtist.cpp.

References AColor::Line().

Referenced by DrawEnvelope().

1484 {
1485  int xx = rect.x + x0;
1486  int yy = rect.y + cy;
1487 
1488  if (y0 < 0) {
1489  if (x0 % 4 != 3) {
1490  AColor::Line(dc, xx, yy, xx, yy + 3);
1491  }
1492  }
1493  else if (y0 > rect.height) {
1494  if (x0 % 4 != 3) {
1495  AColor::Line(dc, xx, yy - 3, xx, yy);
1496  }
1497  }
1498  else {
1499  if (top) {
1500  AColor::Line(dc, xx, yy, xx, yy + 3);
1501  }
1502  else {
1503  AColor::Line(dc, xx, yy - 3, xx, yy);
1504  }
1505  }
1506 }
static void Line(wxDC &dc, wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2)
Definition: AColor.cpp:122
void TrackArtist::DrawIndividualSamples ( wxDC &  dc,
int  leftOffset,
const wxRect &  rect,
float  zoomMin,
float  zoomMax,
bool  dB,
float  dBRange,
const WaveClip clip,
const ZoomInfo zoomInfo,
bool  bigPoints,
bool  showPoints,
bool  muted,
bool  highlight 
)
private

Definition at line 1336 of file TrackArtist.cpp.

References clippedPen, dragsampleBrush, floatSample, WaveClip::GetEnvelope(), WaveClip::GetNumSamples(), WaveClip::GetOffset(), WaveClip::GetRate(), WaveClip::GetSamples(), Envelope::GetValue(), GetWaveYPos(), AColor::Line(), MAX_AUDIO, min(), mSampleDisplay, mShowClipping, muteClippedPen, muteSamplePen, ZoomInfo::PositionToTime(), ArrayOf< X >::reinit(), sampleBrush, samplePen, WaveTrack::StemPlot, ZoomInfo::TimeToPosition(), AColor::uglyBrush, and AColor::uglyPen.

Referenced by DrawClipWaveform().

1343 {
1344  const double toffset = clip->GetOffset();
1345  double rate = clip->GetRate();
1346  const double t0 = std::max(0.0, zoomInfo.PositionToTime(0, -leftOffset) - toffset);
1347  const auto s0 = sampleCount(floor(t0 * rate));
1348  const auto snSamples = clip->GetNumSamples();
1349  if (s0 > snSamples)
1350  return;
1351 
1352  const double t1 = zoomInfo.PositionToTime(rect.width - 1, -leftOffset) - toffset;
1353  const auto s1 = sampleCount(ceil(t1 * rate));
1354 
1355  // Assume size_t will not overflow, else we wouldn't be here drawing the
1356  // few individual samples
1357  auto slen = std::min(snSamples - s0, s1 - s0 + 1).as_size_t();
1358 
1359  if (slen <= 0)
1360  return;
1361 
1362  Floats buffer{ size_t(slen) };
1363  clip->GetSamples((samplePtr)buffer.get(), floatSample, s0, slen,
1364  // Suppress exceptions in this drawing operation:
1365  false);
1366 
1367  ArrayOf<int> xpos{ size_t(slen) };
1368  ArrayOf<int> ypos{ size_t(slen) };
1369  ArrayOf<int> clipped;
1370  int clipcnt = 0;
1371 
1372  if (mShowClipping)
1373  clipped.reinit( size_t(slen) );
1374 
1375  auto &pen = highlight ? AColor::uglyPen : muted ? muteSamplePen : samplePen;
1376  dc.SetPen( pen );
1377 
1378  for (decltype(slen) s = 0; s < slen; s++) {
1379  const double time = toffset + (s + s0).as_double() / rate;
1380  const int xx = // An offset into the rectangle rect
1381  std::max(-10000, std::min(10000,
1382  (int)(zoomInfo.TimeToPosition(time, -leftOffset))));
1383  xpos[s] = xx;
1384 
1385  // Calculate sample as it would be rendered, so quantize time
1386  double value =
1387  clip->GetEnvelope()->GetValue( time, 1.0 / clip->GetRate() );
1388  const double tt = buffer[s] * value;
1389 
1390  if (clipped && mShowClipping && ((tt <= -MAX_AUDIO) || (tt >= MAX_AUDIO)))
1391  clipped[clipcnt++] = xx;
1392  ypos[s] =
1393  std::max(-1,
1394  std::min(rect.height,
1395  GetWaveYPos(tt, zoomMin, zoomMax,
1396  rect.height, dB, true, dBRange, false)));
1397  }
1398 
1399 
1400  if (showPoints) {
1401  // Draw points where spacing is enough
1402  const int tickSize = bigPoints ? 4 : 3;// Bigger ellipses when draggable.
1403  wxRect pr;
1404  pr.width = tickSize;
1405  pr.height = tickSize;
1406  //different colour when draggable.
1407  auto &brush = highlight
1409  : bigPoints ? dragsampleBrush : sampleBrush;
1410  dc.SetBrush( brush );
1411  for (decltype(slen) s = 0; s < slen; s++) {
1412  if (ypos[s] >= 0 && ypos[s] < rect.height) {
1413  pr.x = rect.x + xpos[s] - tickSize/2;
1414  pr.y = rect.y + ypos[s] - tickSize/2;
1415  dc.DrawEllipse(pr);
1416  }
1417  }
1418  }
1419 
1420  if (showPoints && (mSampleDisplay == (int) WaveTrack::StemPlot)) {
1421  // Draw vertical lines
1422  int yZero = GetWaveYPos(0.0, zoomMin, zoomMax, rect.height, dB, true, dBRange, false);
1423  yZero = rect.y + std::max(-1, std::min(rect.height, yZero));
1424  for (decltype(slen) s = 0; s < slen; s++) {
1425  AColor::Line(dc,
1426  rect.x + xpos[s], rect.y + ypos[s],
1427  rect.x + xpos[s], yZero);
1428  }
1429  }
1430  else {
1431  // Connect samples with straight lines
1432  for (decltype(slen) s = 0; s < slen - 1; s++) {
1433  AColor::Line(dc,
1434  rect.x + xpos[s], rect.y + ypos[s],
1435  rect.x + xpos[s + 1], rect.y + ypos[s + 1]);
1436  }
1437  }
1438 
1439  // Draw clipping
1440  if (clipcnt) {
1441  dc.SetPen(muted ? muteClippedPen : clippedPen);
1442  while (--clipcnt >= 0) {
1443  auto s = clipped[clipcnt];
1444  AColor::Line(dc, rect.x + s, rect.y, rect.x + s, rect.y + rect.height);
1445  }
1446  }
1447 }
wxPen muteClippedPen
Definition: TrackArtist.h:210
long mShowClipping
Definition: TrackArtist.h:181
wxPen samplePen
Definition: TrackArtist.h:201
sampleCount GetNumSamples() const
Definition: WaveClip.cpp:448
static wxBrush uglyBrush
Definition: AColor.h:148
void reinit(Integral count, bool initialize=false)
Definition: MemoryX.h:519
wxBrush dragsampleBrush
Definition: TrackArtist.h:195
double PositionToTime(wxInt64 position, wxInt64 origin=0, bool ignoreFisheye=false) const
Definition: ViewInfo.cpp:49
double GetOffset() const
Definition: WaveClip.h:222
static wxPen uglyPen
Definition: AColor.h:147
Envelope * GetEnvelope()
Definition: WaveClip.h:243
int mSampleDisplay
Definition: TrackArtist.h:182
char * samplePtr
Definition: Types.h:202
wxInt64 TimeToPosition(double time, wxInt64 origin=0, bool ignoreFisheye=false) const
STM: Converts a project time to screen x position.
Definition: ViewInfo.cpp:59
int min(int a, int b)
double GetValue(double t, double sampleDur=0) const
Get envelope value at time t.
Definition: Envelope.cpp:1114
static void Line(wxDC &dc, wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2)
Definition: AColor.cpp:122
bool GetSamples(samplePtr buffer, sampleFormat format, sampleCount start, size_t len, bool mayThrow=true) const
Definition: WaveClip.cpp:399
int GetRate() const
Definition: WaveClip.h:210
wxBrush sampleBrush
Definition: TrackArtist.h:193
wxPen clippedPen
Definition: TrackArtist.h:209
wxPen muteSamplePen
Definition: TrackArtist.h:205
int GetWaveYPos(float value, float min, float max, int height, bool dB, bool outer, float dBr, bool clip)
#define MAX_AUDIO
Definition: Audacity.h:219
void TrackArtist::DrawLabelTrack ( TrackPanelDrawingContext context,
const LabelTrack track,
const wxRect &  rect,
const SelectedRegion selectedRegion,
const ZoomInfo zoomInfo 
)
private

Definition at line 3277 of file TrackArtist.cpp.

References LabelTrack::Draw(), Track::GetSelected(), Track::IsSyncLockSelected(), SelectedRegion::t0(), and SelectedRegion::t1().

Referenced by DrawTrack().

3282 {
3283  double sel0 = selectedRegion.t0();
3284  double sel1 = selectedRegion.t1();
3285 
3286  if (!track->GetSelected() && !track->IsSyncLockSelected())
3287  sel0 = sel1 = 0.0;
3288 
3289  track->Draw(context, rect, SelectedRegion(sel0, sel1), zoomInfo);
3290 }
double t0() const
bool GetSelected() const
Definition: Track.h:275
void Draw(TrackPanelDrawingContext &context, const wxRect &r, const SelectedRegion &selectedRegion, const ZoomInfo &zoomInfo) const
Definition: LabelTrack.cpp:784
bool IsSyncLockSelected() const
Definition: Track.cpp:295
double t1() const
Defines a selected portion of a project.
void TrackArtist::DrawMinMaxRMS ( wxDC &  dc,
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  ,
bool  muted 
)
private

Definition at line 1201 of file TrackArtist.cpp.

References clippedPen, GetWaveYPos(), AColor::Line(), MAX_AUDIO, min(), mShowClipping, muteClippedPen, muteRmsPen, muteSamplePen, ArrayOf< X >::reinit(), rmsPen, and samplePen.

Referenced by DrawClipWaveform().

1206 {
1207  // Display a line representing the
1208  // min and max of the samples in this region
1209  int lasth1 = std::numeric_limits<int>::max();
1210  int lasth2 = std::numeric_limits<int>::min();
1211  int h1;
1212  int h2;
1213  ArrayOf<int> r1{ size_t(rect.width) };
1214  ArrayOf<int> r2{ size_t(rect.width) };
1215  ArrayOf<int> clipped;
1216  int clipcnt = 0;
1217 
1218  if (mShowClipping) {
1219  clipped.reinit( size_t(rect.width) );
1220  }
1221 
1222  long pixAnimOffset = (long)fabs((double)(wxDateTime::Now().GetTicks() * -10)) +
1223  wxDateTime::Now().GetMillisecond() / 100; //10 pixels a second
1224 
1225  bool drawStripes = true;
1226  bool drawWaveform = true;
1227 
1228  dc.SetPen(muted ? muteSamplePen : samplePen);
1229  for (int x0 = 0; x0 < rect.width; ++x0) {
1230  int xx = rect.x + x0;
1231  double v;
1232  v = min[x0] * env[x0];
1233  if (clipped && mShowClipping && (v <= -MAX_AUDIO))
1234  {
1235  if (clipcnt == 0 || clipped[clipcnt - 1] != xx) {
1236  clipped[clipcnt++] = xx;
1237  }
1238  }
1239  h1 = GetWaveYPos(v, zoomMin, zoomMax,
1240  rect.height, dB, true, dBRange, true);
1241 
1242  v = max[x0] * env[x0];
1243  if (clipped && mShowClipping && (v >= MAX_AUDIO))
1244  {
1245  if (clipcnt == 0 || clipped[clipcnt - 1] != xx) {
1246  clipped[clipcnt++] = xx;
1247  }
1248  }
1249  h2 = GetWaveYPos(v, zoomMin, zoomMax,
1250  rect.height, dB, true, dBRange, true);
1251 
1252  // JKC: This adjustment to h1 and h2 ensures that the drawn
1253  // waveform is continuous.
1254  if (x0 > 0) {
1255  if (h1 < lasth2) {
1256  h1 = lasth2 - 1;
1257  }
1258  if (h2 > lasth1) {
1259  h2 = lasth1 + 1;
1260  }
1261  }
1262  lasth1 = h1;
1263  lasth2 = h2;
1264 
1265  r1[x0] = GetWaveYPos(-rms[x0] * env[x0], zoomMin, zoomMax,
1266  rect.height, dB, true, dBRange, true);
1267  r2[x0] = GetWaveYPos(rms[x0] * env[x0], zoomMin, zoomMax,
1268  rect.height, dB, true, dBRange, true);
1269  // Make sure the rms isn't larger than the waveform min/max
1270  if (r1[x0] > h1 - 1) {
1271  r1[x0] = h1 - 1;
1272  }
1273  if (r2[x0] < h2 + 1) {
1274  r2[x0] = h2 + 1;
1275  }
1276  if (r2[x0] > r1[x0]) {
1277  r2[x0] = r1[x0];
1278  }
1279 
1280  if (bl[x0] <= -1) {
1281  if (drawStripes) {
1282  // TODO:unify with buffer drawing.
1283  dc.SetPen((bl[x0] % 2) ? muteSamplePen : samplePen);
1284  for (int yy = 0; yy < rect.height / 25 + 1; ++yy) {
1285  // we are drawing over the buffer, but I think DrawLine takes care of this.
1286  AColor::Line(dc,
1287  xx,
1288  rect.y + 25 * yy + (x0 /*+pixAnimOffset*/) % 25,
1289  xx,
1290  rect.y + 25 * yy + (x0 /*+pixAnimOffset*/) % 25 + 6); //take the min so we don't draw past the edge
1291  }
1292  }
1293 
1294  // 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.
1295  // 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.
1296  if (drawWaveform) {
1297  int triX;
1298  dc.SetPen(samplePen);
1299  triX = fabs((double)((x0 + pixAnimOffset) % (2 * rect.height)) - rect.height) + rect.height;
1300  for (int yy = 0; yy < rect.height; ++yy) {
1301  if ((yy + triX) % rect.height == 0) {
1302  dc.DrawPoint(xx, rect.y + yy);
1303  }
1304  }
1305  }
1306 
1307  // Restore the pen for remaining pixel columns!
1308  dc.SetPen(muted ? muteSamplePen : samplePen);
1309  }
1310  else {
1311  AColor::Line(dc, xx, rect.y + h2, xx, rect.y + h1);
1312  }
1313  }
1314 
1315  // Stroke rms over the min-max
1316  dc.SetPen(muted ? muteRmsPen : rmsPen);
1317  for (int x0 = 0; x0 < rect.width; ++x0) {
1318  int xx = rect.x + x0;
1319  if (bl[x0] <= -1) {
1320  }
1321  else if (r1[x0] != r2[x0]) {
1322  AColor::Line(dc, xx, rect.y + r2[x0], xx, rect.y + r1[x0]);
1323  }
1324  }
1325 
1326  // Draw the clipping lines
1327  if (clipcnt) {
1328  dc.SetPen(muted ? muteClippedPen : clippedPen);
1329  while (--clipcnt >= 0) {
1330  int xx = clipped[clipcnt];
1331  AColor::Line(dc, xx, rect.y, xx, rect.y + rect.height);
1332  }
1333  }
1334 }
wxPen muteClippedPen
Definition: TrackArtist.h:210
long mShowClipping
Definition: TrackArtist.h:181
wxPen samplePen
Definition: TrackArtist.h:201
wxPen muteRmsPen
Definition: TrackArtist.h:203
void reinit(Integral count, bool initialize=false)
Definition: MemoryX.h:519
int min(int a, int b)
static void Line(wxDC &dc, wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2)
Definition: AColor.cpp:122
wxPen rmsPen
Definition: TrackArtist.h:202
wxPen clippedPen
Definition: TrackArtist.h:209
wxPen muteSamplePen
Definition: TrackArtist.h:205
int GetWaveYPos(float value, float min, float max, int height, bool dB, bool outer, float dBr, bool clip)
#define MAX_AUDIO
Definition: Audacity.h:219
void TrackArtist::DrawNegativeOffsetTrackArrows ( wxDC &  dc,
const wxRect &  rect 
)
private

Definition at line 1045 of file TrackArtist.cpp.

References AColor::Line().

Referenced by DrawClipWaveform().

1046 {
1047  // Draws two black arrows on the left side of the track to
1048  // indicate the user that the track has been time-shifted
1049  // to the left beyond t=0.0.
1050 
1051  dc.SetPen(*wxBLACK_PEN);
1052  AColor::Line(dc,
1053  rect.x + 2, rect.y + 6,
1054  rect.x + 8, rect.y + 6);
1055  AColor::Line(dc,
1056  rect.x + 2, rect.y + 6,
1057  rect.x + 6, rect.y + 2);
1058  AColor::Line(dc,
1059  rect.x + 2, rect.y + 6,
1060  rect.x + 6, rect.y + 10);
1061  AColor::Line(dc,
1062  rect.x + 2, rect.y + rect.height - 8,
1063  rect.x + 8, rect.y + rect.height - 8);
1064  AColor::Line(dc,
1065  rect.x + 2, rect.y + rect.height - 8,
1066  rect.x + 6, rect.y + rect.height - 4);
1067  AColor::Line(dc,
1068  rect.x + 2, rect.y + rect.height - 8,
1069  rect.x + 6, rect.y + rect.height - 12);
1070 }
static void Line(wxDC &dc, wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2)
Definition: AColor.cpp:122
void TrackArtist::DrawSpectrum ( const WaveTrack track,
wxDC &  dc,
const wxRect &  rect,
const SelectedRegion selectedRegion,
const ZoomInfo zoomInfo 
)
private

Definition at line 2106 of file TrackArtist.cpp.

References blankBrush, blankSelectedBrush, DrawBackgroundWithSelection(), DrawClipSpectrum(), and WaveTrack::GetClips().

Referenced by DrawTrack().

2111 {
2113  selectedRegion, zoomInfo);
2114 
2115  WaveTrackCache cache(Track::Pointer<const WaveTrack>(track));
2116  for (const auto &clip: track->GetClips()) {
2117  DrawClipSpectrum(cache, clip.get(), dc, rect, selectedRegion, zoomInfo);
2118  }
2119 }
void DrawClipSpectrum(WaveTrackCache &cache, const WaveClip *clip, wxDC &dc, const wxRect &rect, const SelectedRegion &selectedRegion, const ZoomInfo &zoomInfo)
static void DrawBackgroundWithSelection(wxDC *dc, const wxRect &rect, const Track *track, wxBrush &selBrush, wxBrush &unselBrush, const SelectedRegion &selectedRegion, const ZoomInfo &zoomInfo)
wxBrush blankSelectedBrush
Definition: TrackArtist.h:197
WaveClipHolders & GetClips()
Definition: WaveTrack.h:364
wxBrush blankBrush
Definition: TrackArtist.h:190
void TrackArtist::DrawSyncLockTiles ( wxDC *  dc,
wxRect  rect 
)
static

Definition at line 3332 of file TrackArtist.cpp.

References ThemeBase::Image(), and theTheme.

Referenced by DrawBackgroundWithSelection(), and DrawWaveformBackground().

3333 {
3334  wxBitmap syncLockBitmap(theTheme.Image(bmpSyncLockSelTile));
3335 
3336  // Grid spacing is a bit smaller than actual image size
3337  int gridW = syncLockBitmap.GetWidth() - 6;
3338  int gridH = syncLockBitmap.GetHeight() - 8;
3339 
3340  // Horizontal position within the grid, modulo its period
3341  int blockX = (rect.x / gridW) % 5;
3342 
3343  // Amount to offset drawing of first column
3344  int xOffset = rect.x % gridW;
3345  if (xOffset < 0) xOffset += gridW;
3346 
3347  // Check if we're missing an extra column to the left (this can happen
3348  // because the tiles are bigger than the grid spacing)
3349  bool extraCol = false;
3350  if (syncLockBitmap.GetWidth() - gridW > xOffset) {
3351  extraCol = true;
3352  xOffset += gridW;
3353  blockX = (blockX - 1) % 5;
3354  }
3355  // Make sure blockX is non-negative
3356  if (blockX < 0) blockX += 5;
3357 
3358  int xx = 0;
3359  while (xx < rect.width) {
3360  int width = syncLockBitmap.GetWidth() - xOffset;
3361  if (xx + width > rect.width)
3362  width = rect.width - xx;
3363 
3364  //
3365  // Draw each row in this column
3366  //
3367 
3368  // Vertical position in the grid, modulo its period
3369  int blockY = (rect.y / gridH) % 5;
3370 
3371  // Amount to offset drawing of first row
3372  int yOffset = rect.y % gridH;
3373  if (yOffset < 0) yOffset += gridH;
3374 
3375  // Check if we're missing an extra row on top (this can happen because
3376  // the tiles are bigger than the grid spacing)
3377  bool extraRow = false;
3378  if (syncLockBitmap.GetHeight() - gridH > yOffset) {
3379  extraRow = true;
3380  yOffset += gridH;
3381  blockY = (blockY - 1) % 5;
3382  }
3383  // Make sure blockY is non-negative
3384  if (blockY < 0) blockY += 5;
3385 
3386  int yy = 0;
3387  while (yy < rect.height)
3388  {
3389  int height = syncLockBitmap.GetHeight() - yOffset;
3390  if (yy + height > rect.height)
3391  height = rect.height - yy;
3392 
3393  // AWD: draw blocks according to our pattern
3394  if ((blockX == 0 && blockY == 0) || (blockX == 2 && blockY == 1) ||
3395  (blockX == 4 && blockY == 2) || (blockX == 1 && blockY == 3) ||
3396  (blockX == 3 && blockY == 4))
3397  {
3398 
3399  // Do we need to get a sub-bitmap?
3400  if (width != syncLockBitmap.GetWidth() || height != syncLockBitmap.GetHeight()) {
3401  wxBitmap subSyncLockBitmap =
3402  syncLockBitmap.GetSubBitmap(wxRect(xOffset, yOffset, width, height));
3403  dc->DrawBitmap(subSyncLockBitmap, rect.x + xx, rect.y + yy, true);
3404  }
3405  else {
3406  dc->DrawBitmap(syncLockBitmap, rect.x + xx, rect.y + yy, true);
3407  }
3408  }
3409 
3410  // Updates for next row
3411  if (extraRow) {
3412  // Second offset row, still at y = 0; no more extra rows
3413  yOffset -= gridH;
3414  extraRow = false;
3415  }
3416  else {
3417  // Move on in y, no more offset rows
3418  yy += gridH - yOffset;
3419  yOffset = 0;
3420  }
3421  blockY = (blockY + 1) % 5;
3422  }
3423 
3424  // Updates for next column
3425  if (extraCol) {
3426  // Second offset column, still at x = 0; no more extra columns
3427  xOffset -= gridW;
3428  extraCol = false;
3429  }
3430  else {
3431  // Move on in x, no more offset rows
3432  xx += gridW - xOffset;
3433  xOffset = 0;
3434  }
3435  blockX = (blockX + 1) % 5;
3436  }
3437 }
AUDACITY_DLL_API Theme theTheme
Definition: Theme.cpp:209
wxImage & Image(int iIndex)
Definition: Theme.cpp:1251
void TrackArtist::DrawTimeSlider ( wxDC &  dc,
const wxRect &  rect,
bool  rightwards,
bool  highlight 
)
private

Definition at line 2050 of file TrackArtist.cpp.

References AColor::Dark(), AColor::Light(), and AColor::Line().

Referenced by DrawWaveform().

2053 {
2054  const int border = 3; // 3 pixels all round.
2055  const int width = 6; // width of the drag box.
2056  const int taper = 6; // how much the box tapers by.
2057  const int barSpacing = 4; // how far apart the bars are.
2058  const int barWidth = 3;
2059  const int xFlat = 3;
2060 
2061  //Enough space to draw in?
2062  if (rect.height <= ((taper+border + barSpacing) * 2)) {
2063  return;
2064  }
2065  if (rect.width <= (width * 2 + border * 3)) {
2066  return;
2067  }
2068 
2069  // The draggable box is tapered towards the direction you drag it.
2070  int leftTaper = rightwards ? 0 : 6;
2071  int rightTaper = rightwards ? 6 : 0;
2072 
2073  int xLeft = rightwards ? (rect.x + border - 2)
2074  : (rect.x + rect.width + 1 - (border + width));
2075  int yTop = rect.y + border;
2076  int yBot = rect.y + rect.height - border - 1;
2077 
2078  AColor::Light(&dc, false, highlight);
2079  AColor::Line(dc, xLeft, yBot - leftTaper, xLeft, yTop + leftTaper);
2080  AColor::Line(dc, xLeft, yTop + leftTaper, xLeft + xFlat, yTop);
2081  AColor::Line(dc, xLeft + xFlat, yTop, xLeft + width, yTop + rightTaper);
2082 
2083  AColor::Dark(&dc, false, highlight);
2084  AColor::Line(dc, xLeft + width, yTop + rightTaper, xLeft + width, yBot - rightTaper);
2085  AColor::Line(dc, xLeft + width, yBot - rightTaper, xLeft + width-xFlat, yBot);
2086  AColor::Line(dc, xLeft + width - xFlat, yBot, xLeft, yBot - leftTaper);
2087 
2088  int firstBar = yTop + taper + taper / 2;
2089  int nBars = (yBot - yTop - taper * 3) / barSpacing + 1;
2090  xLeft += (width - barWidth + 1) / 2;
2091  int yy;
2092  int i;
2093 
2094  AColor::Light(&dc, false, highlight);
2095  for (i = 0;i < nBars; i++) {
2096  yy = firstBar + barSpacing * i;
2097  AColor::Line(dc, xLeft, yy, xLeft + barWidth, yy);
2098  }
2099  AColor::Dark(&dc, false, highlight);
2100  for(i = 0;i < nBars; i++){
2101  yy = firstBar + barSpacing * i + 1;
2102  AColor::Line(dc, xLeft, yy, xLeft + barWidth, yy);
2103  }
2104 }
static void Dark(wxDC *dc, bool selected, bool highlight=false)
Definition: AColor.cpp:338
static void Line(wxDC &dc, wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2)
Definition: AColor.cpp:122
static void Light(wxDC *dc, bool selected, bool highlight=false)
Definition: AColor.cpp:308
void TrackArtist::DrawTimeTrack ( TrackPanelDrawingContext context,
const TimeTrack track,
const wxRect &  rect,
const ZoomInfo zoomInfo 
)
private

Definition at line 3292 of file TrackArtist.cpp.

References TimeTrack::Draw(), Envelope::DrawPoints(), TimeTrack::GetDisplayLog(), TimeTrack::GetEnvelope(), TimeTrack::GetRangeLower(), TimeTrack::GetRangeUpper(), LINEAR_TO_DB, and mdBrange.

Referenced by DrawTrack().

3296 {
3297  track->Draw(context, rect, zoomInfo);
3298  wxRect envRect = rect;
3299  envRect.height -= 2;
3300  double lower = track->GetRangeLower(), upper = track->GetRangeUpper();
3301  if(track->GetDisplayLog()) {
3302  // MB: silly way to undo the work of GetWaveYPos while still getting a logarithmic scale
3303  lower = LINEAR_TO_DB(std::max(1.0e-7, lower)) / mdBrange + 1.0;
3304  upper = LINEAR_TO_DB(std::max(1.0e-7, upper)) / mdBrange + 1.0;
3305  }
3306  track->GetEnvelope()->DrawPoints
3307  (context, envRect, zoomInfo,
3308  track->GetDisplayLog(), mdBrange, lower, upper, false);
3309 }
bool GetDisplayLog() const
Definition: TimeTrack.h:133
void DrawPoints(TrackPanelDrawingContext &context, const wxRect &r, const ZoomInfo &zoomInfo, bool dB, double dBRange, float zoomMin, float zoomMax, bool mirrored) const
TODO: This should probably move to track artist.
Definition: Envelope.cpp:322
double GetRangeLower() const
Definition: TimeTrack.h:127
void Draw(TrackPanelDrawingContext &context, const wxRect &r, const ZoomInfo &zoomInfo) const
Definition: TimeTrack.cpp:265
double GetRangeUpper() const
Definition: TimeTrack.h:128
float mdBrange
Definition: TrackArtist.h:180
#define LINEAR_TO_DB(x)
Definition: Audacity.h:217
Envelope * GetEnvelope()
Definition: TimeTrack.h:90
void TrackArtist::DrawTrack ( TrackPanelDrawingContext context,
const Track t,
const wxRect &  rect,
const SelectedRegion selectedRegion,
const ZoomInfo zoomInfo,
bool  drawEnvelope,
bool  bigPoints,
bool  drawSliders,
bool  hasSolo 
)

Definition at line 445 of file TrackArtist.cpp.

References ThemeBase::Colour(), TrackPanelDrawingContext::dc, DrawLabelTrack(), DrawSpectrum(), DrawTimeTrack(), DrawWaveform(), WaveTrack::GetClips(), WaveTrack::GetDisplay(), Track::GetKind(), Track::GetLink(), Track::GetLinked(), PlayableTrack::GetMute(), Track::GetName(), PlayableTrack::GetSolo(), Track::Label, mbShowTrackNameInWaveform, WaveTrack::Spectrum, theTheme, Track::Time, AColor::UseThemeColour(), Track::Wave, and WaveTrack::Waveform.

Referenced by DrawTracks(), and AudacityPrintout::OnPrintPage().

454 {
455  auto &dc = context.dc;
456  switch (t->GetKind()) {
457  case Track::Wave:
458  {
459  const WaveTrack* wt = static_cast<const WaveTrack*>(t);
460  for (const auto &clip : wt->GetClips()) {
461  clip->ClearDisplayRect();
462  }
463 
464  bool muted = (hasSolo || wt->GetMute()) &&
465  !wt->GetSolo();
466 
467 #if defined(__WXMAC__)
468  wxAntialiasMode aamode = dc.GetGraphicsContext()->GetAntialiasMode();
469  dc.GetGraphicsContext()->SetAntialiasMode(wxANTIALIAS_NONE);
470 #endif
471 
472  switch (wt->GetDisplay()) {
473  case WaveTrack::Waveform:
474  DrawWaveform(context, wt, rect, selectedRegion, zoomInfo,
475  drawEnvelope, bigPoints, drawSliders, muted);
476  break;
477  case WaveTrack::Spectrum:
478  DrawSpectrum(wt, dc, rect, selectedRegion, zoomInfo);
479  break;
480  default:
481  wxASSERT(false);
482  }
483 
484 #if defined(__WXMAC__)
485  dc.GetGraphicsContext()->SetAntialiasMode(aamode);
486 #endif
487 
489  // Exclude right channel of stereo track
490  !(!wt->GetLinked() && wt->GetLink()) &&
491  // Exclude empty name.
492  !wt->GetName().IsEmpty()) {
493  wxBrush Brush;
494  wxCoord x,y;
495  wxFont labelFont(12, wxSWISS, wxNORMAL, wxNORMAL);
496  dc.SetFont(labelFont);
497  dc.GetTextExtent( wt->GetName(), &x, &y );
498  dc.SetTextForeground(theTheme.Colour( clrTrackPanelText ));
499  // A nice improvement would be to draw the shield / background translucently.
500  AColor::UseThemeColour( &dc, clrTrackInfoSelected, clrTrackPanelText );
501  dc.DrawRoundedRectangle( wxPoint( rect.x+7, rect.y+1 ), wxSize( x+16, y+4), 8.0 );
502  dc.DrawText (wt->GetName(), rect.x+15, rect.y+3); // move right 15 pixels to avoid overwriting <- symbol
503  }
504  break; // case Wave
505  }
506  #ifdef USE_MIDI
507  case Track::Note:
508  {
509  auto nt = static_cast<const NoteTrack *>(t);
510  bool muted = false;
511 #ifdef EXPERIMENTAL_MIDI_OUT
512  muted = (hasSolo || nt->GetMute()) && !nt->GetSolo();
513 #endif
514  DrawNoteTrack((NoteTrack *)t, dc, rect, selectedRegion, zoomInfo, muted);
515  break;
516  }
517  #endif // USE_MIDI
518  case Track::Label:
519  DrawLabelTrack(context, (LabelTrack *)t, rect, selectedRegion, zoomInfo);
520  break;
521  case Track::Time:
522  DrawTimeTrack(context, (TimeTrack *)t, rect, zoomInfo);
523  break;
524  }
525 }
bool GetSolo() const
Definition: Track.h:383
AUDACITY_DLL_API Theme theTheme
Definition: Theme.cpp:209
void DrawLabelTrack(TrackPanelDrawingContext &context, const LabelTrack *track, const wxRect &rect, const SelectedRegion &selectedRegion, const ZoomInfo &zoomInfo)
bool GetLinked() const
Definition: Track.h:278
void DrawWaveform(TrackPanelDrawingContext &context, const WaveTrack *track, const wxRect &rect, const SelectedRegion &selectedRegion, const ZoomInfo &zoomInfo, bool drawEnvelope, bool bigPoints, bool drawSliders, bool muted)
bool mbShowTrackNameInWaveform
Definition: TrackArtist.h:183
virtual int GetKind() const
Definition: Track.h:329
A LabelTrack is a Track that holds labels (LabelStruct).
Definition: LabelTrack.h:113
A kind of Track used to 'warp time'.
Definition: TimeTrack.h:29
A Track that contains audio waveform data.
Definition: WaveTrack.h:60
WaveClipHolders & GetClips()
Definition: WaveTrack.h:364
void DrawSpectrum(const WaveTrack *track, wxDC &dc, const wxRect &rect, const SelectedRegion &selectedRegion, const ZoomInfo &zoomInfo)
wxString GetName() const
Definition: Track.h:270
static void UseThemeColour(wxDC *dc, int iBrush, int iPen=-1)
Definition: AColor.cpp:289
void DrawTimeTrack(TrackPanelDrawingContext &context, const TimeTrack *track, const wxRect &rect, const ZoomInfo &zoomInfo)
Track * GetLink() const
Definition: Track.cpp:269
bool GetMute() const
Definition: Track.h:382
wxColour & Colour(int iIndex)
Definition: Theme.cpp:1225
WaveTrackDisplay GetDisplay() const
Definition: WaveTrack.h:593
A Track that is used for Midi notes. (Somewhat old code).
void TrackArtist::DrawTracks ( TrackPanelDrawingContext context,
TrackList tracks,
Track start,
const wxRegion &  reg,
const wxRect &  rect,
const wxRect &  clip,
const SelectedRegion selectedRegion,
const ZoomInfo zoomInfo,
bool  drawEnvelope,
bool  bigPoints,
bool  drawSliders 
)

Definition at line 342 of file TrackArtist.cpp.

References DrawTrack(), TrackList::FindPendingChangedTrack(), TrackListIterator::First(), Track::GetHeight(), Track::GetId(), Track::GetLink(), Track::GetLinked(), Track::GetY(), gPrefs, mbShowTrackNameInWaveform, mMarginBottom, mMarginLeft, mMarginRight, mMarginTop, TrackListIterator::Next(), TrackListIterator::StartWith(), and ZoomInfo::vpos.

353 {
354  wxRect trackRect = rect;
355  wxRect stereoTrackRect;
356  TrackListIterator iter(tracks);
357  Track *t;
358 
359  bool hasSolo = false;
360  for (t = iter.First(); t; t = iter.Next()) {
361  auto other = tracks->FindPendingChangedTrack(t->GetId());
362  if (other)
363  t = other.get();
364  auto pt = dynamic_cast<const PlayableTrack *>(t);
365  if (pt && pt->GetSolo()) {
366  hasSolo = true;
367  break;
368  }
369  }
370 
371 #if defined(DEBUG_CLIENT_AREA)
372  // Change the +0 to +1 or +2 to see the bounding box
373  mMarginLeft = 1+0; mMarginTop = 5+0; mMarginRight = 6+0; mMarginBottom = 2+0;
374 
375  // This just shows what the passed in rectangles enclose
376  dc.SetPen(wxColour(*wxGREEN));
377  dc.SetBrush(*wxTRANSPARENT_BRUSH);
378  dc.DrawRectangle(rect);
379  dc.SetPen(wxColour(*wxBLUE));
380  dc.SetBrush(*wxTRANSPARENT_BRUSH);
381  dc.DrawRectangle(clip);
382 #endif
383 
384  gPrefs->Read(wxT("/GUI/ShowTrackNameInWaveform"), &mbShowTrackNameInWaveform, false);
385 
386  t = iter.StartWith(start);
387  while (t) {
388  auto other = tracks->FindPendingChangedTrack(t->GetId());
389  if (other)
390  t = other.get();
391  trackRect.y = t->GetY() - zoomInfo.vpos;
392  trackRect.height = t->GetHeight();
393 
394  if (trackRect.y > clip.GetBottom() && !t->GetLinked()) {
395  break;
396  }
397 
398 #if defined(DEBUG_CLIENT_AREA)
399  // Filled rectangle to show the interior of the client area
400  wxRect zr = trackRect;
401  zr.x+=1; zr.y+=5; zr.width-=7; zr.height-=7;
402  dc.SetPen(*wxCYAN_PEN);
403  dc.SetBrush(*wxRED_BRUSH);
404  dc.DrawRectangle(zr);
405 #endif
406 
407  stereoTrackRect = trackRect;
408 
409  // For various reasons, the code will break if we display one
410  // of a stereo pair of tracks but not the other - for example,
411  // if you try to edit the envelope of one track when its linked
412  // pair is off the screen, then it won't be able to edit the
413  // offscreen envelope. So we compute the rect of the track and
414  // its linked partner, and see if any part of that rect is on-screen.
415  // If so, we draw both. Otherwise, we can safely draw neither.
416 
417  Track *link = t->GetLink();
418  if (link) {
419  if (t->GetLinked()) {
420  // If we're the first track
421  stereoTrackRect.height += link->GetHeight();
422  }
423  else {
424  // We're the second of two
425  stereoTrackRect.y -= link->GetHeight();
426  stereoTrackRect.height += link->GetHeight();
427  }
428  }
429 
430  if (stereoTrackRect.Intersects(clip) && reg.Contains(stereoTrackRect)) {
431  wxRect rr = trackRect;
432  rr.x += mMarginLeft;
433  rr.y += mMarginTop;
434  rr.width -= (mMarginLeft + mMarginRight);
435  rr.height -= (mMarginTop + mMarginBottom);
436  DrawTrack(context, t, rr,
437  selectedRegion, zoomInfo,
438  drawEnvelope, bigPoints, drawSliders, hasSolo);
439  }
440 
441  t = iter.Next();
442  }
443 }
AudacityPrefs * gPrefs
Definition: Prefs.cpp:73
TrackId GetId() const
Definition: Track.h:128
bool GetLinked() const
Definition: Track.h:278
bool mbShowTrackNameInWaveform
Definition: TrackArtist.h:183
void DrawTrack(TrackPanelDrawingContext &context, const Track *t, const wxRect &rect, const SelectedRegion &selectedRegion, const ZoomInfo &zoomInfo, bool drawEnvelope, bool bigPoints, bool drawSliders, bool hasSolo)
Fundamental data object of Audacity, placed in the TrackPanel. Classes derived form it include the Wa...
Definition: Track.h:101
std::shared_ptr< Track > FindPendingChangedTrack(TrackId id) const
Definition: Track.cpp:1556
An AudioTrack that can be played and stopped.
Definition: Track.h:375
int vpos
Definition: ViewInfo.h:45
An iterator for a TrackList.
Definition: Track.h:401
Track * GetLink() const
Definition: Track.cpp:269
int GetY() const
Definition: Track.cpp:154
int mMarginRight
Definition: TrackArtist.h:187
int mMarginBottom
Definition: TrackArtist.h:188
int GetHeight() const
Definition: Track.cpp:180
void TrackArtist::DrawVRuler ( TrackPanelDrawingContext context,
const Track t,
wxRect &  rect 
)

Definition at line 528 of file TrackArtist.cpp.

References AColor::BevelTrackInfo(), ThemeBase::Colour(), TrackPanelDrawingContext::dc, Track::GetKind(), Track::Label, TrackPanelDrawingContext::lastState, AColor::Line(), theTheme, Track::Time, AColor::uglyPen, RefreshCode::UpdateVRuler, Track::vrulerSize, and Track::Wave.

529 {
530  auto dc = &context.dc;
531  bool highlight = false;
532 #ifdef EXPERIMENTAL_TRACK_PANEL_HIGHLIGHTING
533  highlight = rect.Contains(context.lastState.GetPosition());
534 #endif
535 
536  int kind = t->GetKind();
537 
538  // Label and Time tracks do not have a vruler
539  // But give it a beveled area
540  if (kind == Track::Label) {
541  wxRect bev = rect;
542  bev.Inflate(-1, 0);
543  bev.width += 1;
544  AColor::BevelTrackInfo(*dc, true, bev);
545 
546  return;
547  }
548 
549  // Time tracks
550  if (kind == Track::Time) {
551  wxRect bev = rect;
552  bev.Inflate(-1, 0);
553  bev.width += 1;
554  AColor::BevelTrackInfo(*dc, true, bev);
555 
556  // Right align the ruler
557  wxRect rr = rect;
558  rr.width--;
559  if (t->vrulerSize.GetWidth() < rect.GetWidth()) {
560  int adj = rr.GetWidth() - t->vrulerSize.GetWidth();
561  rr.x += adj;
562  rr.width -= adj;
563  }
564 
565  UpdateVRuler(t, rr);
566  vruler->SetTickColour( theTheme.Colour( clrTrackPanelText ));
567  vruler->Draw(*dc);
568 
569  return;
570  }
571 
572  // All waves have a ruler in the info panel
573  // The ruler needs a bevelled surround.
574  if (kind == Track::Wave) {
575  wxRect bev = rect;
576  bev.Inflate(-1, 0);
577  bev.width += 1;
578  AColor::BevelTrackInfo(*dc, true, bev, highlight);
579 
580  // Right align the ruler
581  wxRect rr = rect;
582  rr.width--;
583  if (t->vrulerSize.GetWidth() < rect.GetWidth()) {
584  int adj = rr.GetWidth() - t->vrulerSize.GetWidth();
585  rr.x += adj;
586  rr.width -= adj;
587  }
588 
589  UpdateVRuler(t, rr);
590  vruler->SetTickColour( theTheme.Colour( clrTrackPanelText ));
591  vruler->Draw(*dc);
592 
593  return;
594  }
595 
596 #ifdef USE_MIDI
597  // The note track draws a vertical keyboard to label pitches
598  if (kind == Track::Note) {
599  UpdateVRuler(t, rect);
600 
601  dc->SetPen(highlight ? AColor::uglyPen : *wxTRANSPARENT_PEN);
602  dc->SetBrush(*wxWHITE_BRUSH);
603  wxRect bev = rect;
604  bev.x++;
605  bev.width--;
606  dc->DrawRectangle(bev);
607 
608  rect.y += 1;
609  rect.height -= 1;
610 
611  //int bottom = GetBottom((NoteTrack *) t, rect);
612  const NoteTrack *track = (NoteTrack *) t;
613  track->PrepareIPitchToY(rect);
614 
615  wxPen hilitePen;
616  hilitePen.SetColour(120, 120, 120);
617  wxBrush blackKeyBrush;
618  blackKeyBrush.SetColour(70, 70, 70);
619 
620  dc->SetBrush(blackKeyBrush);
621 
622  int fontSize = 10;
623 #ifdef __WXMSW__
624  fontSize = 8;
625 #endif
626 
627  wxFont labelFont(fontSize, wxSWISS, wxNORMAL, wxNORMAL);
628  dc->SetFont(labelFont);
629 
630  int octave = 0;
631  int obottom = track->GetOctaveBottom(octave);
632  int marg = track->GetNoteMargin(rect.height);
633  //IPITCH_TO_Y(octave * 12) + PITCH_HEIGHT + 1;
634  while (obottom >= rect.y) {
635  dc->SetPen(*wxBLACK_PEN);
636  for (int white = 0; white < 7; white++) {
637  int pos = track->GetWhitePos(white);
638  if (obottom - pos > rect.y + marg + 1 &&
639  // don't draw too close to margin line -- it's annoying
640  obottom - pos < rect.y + rect.height - marg - 3)
641  AColor::Line(*dc, rect.x, obottom - pos,
642  rect.x + rect.width, obottom - pos);
643  }
644  wxRect br = rect;
645  br.height = track->GetPitchHeight(1);
646  br.x++;
647  br.width = 17;
648  for (int black = 0; black < 5; black++) {
649  br.y = obottom - track->GetBlackPos(black);
650  if (br.y > rect.y + marg - 2 && br.y + br.height < rect.y + rect.height - marg) {
651  dc->SetPen(hilitePen);
652  dc->DrawRectangle(br);
653  dc->SetPen(*wxBLACK_PEN);
654  AColor::Line(*dc,
655  br.x + 1, br.y + br.height - 1,
656  br.x + br.width - 1, br.y + br.height - 1);
657  AColor::Line(*dc,
658  br.x + br.width - 1, br.y + 1,
659  br.x + br.width - 1, br.y + br.height - 1);
660  }
661  }
662 
663  if (octave >= 1 && octave <= 10) {
664  wxString s;
665  // ISO standard: A440 is in the 4th octave, denoted
666  // A4 <- the "4" should be a subscript.
667  s.Printf(wxT("C%d"), octave - 1);
668  wxCoord width, height;
669  dc->GetTextExtent(s, &width, &height);
670  if (obottom - height + 4 > rect.y &&
671  obottom + 4 < rect.y + rect.height) {
672  dc->SetTextForeground(wxColour(60, 60, 255));
673  dc->DrawText(s, rect.x + rect.width - width,
674  obottom - height + 2);
675  }
676  }
677  obottom = track->GetOctaveBottom(++octave);
678  }
679  // draw lines delineating the out-of-bounds margins
680  dc->SetPen(*wxBLACK_PEN);
681  // you would think the -1 offset here should be -2 to match the
682  // adjustment to rect.y (see above), but -1 produces correct output
683  AColor::Line(*dc, rect.x, rect.y + marg - 1, rect.x + rect.width, rect.y + marg - 1);
684  // since the margin gives us the bottom of the line,
685  // the extra -1 gets us to the top
686  AColor::Line(*dc, rect.x, rect.y + rect.height - marg - 1,
687  rect.x + rect.width, rect.y + rect.height - marg - 1);
688 
689  }
690 #endif // USE_MIDI
691 
692 }
AUDACITY_DLL_API Theme theTheme
Definition: Theme.cpp:209
std::unique_ptr< Ruler > vruler
Definition: TrackArtist.h:213
static wxPen uglyPen
Definition: AColor.h:147
virtual int GetKind() const
Definition: Track.h:329
static void Line(wxDC &dc, wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2)
Definition: AColor.cpp:122
static void BevelTrackInfo(wxDC &dc, bool up, const wxRect &r, bool highlight=false)
Definition: AColor.cpp:262
wxColour & Colour(int iIndex)
Definition: Theme.cpp:1225
wxSize vrulerSize
Definition: Track.h:175
void UpdateVRuler(const Track *t, wxRect &rect)
A Track that is used for Midi notes. (Somewhat old code).
void TrackArtist::DrawWaveform ( TrackPanelDrawingContext context,
const WaveTrack track,
const wxRect &  rect,
const SelectedRegion selectedRegion,
const ZoomInfo zoomInfo,
bool  drawEnvelope,
bool  bigPoints,
bool  drawSliders,
bool  muted 
)
private

Definition at line 1510 of file TrackArtist.cpp.

References blankBrush, blankSelectedBrush, TrackPanelDrawingContext::dc, DrawBackgroundWithSelection(), DrawClipWaveform(), DrawTimeSlider(), WaveTrack::GetCachedLocations(), WaveTrack::GetClips(), CutlineHandle::GetTrack(), WaveTrack::GetWaveformSettings(), TimeShiftHandle::IsGripHit(), WaveformSettings::isLinear(), AColor::Line(), WaveTrackLocation::locationCutLine, TrackPanelDrawingContext::target, AColor::uglyPen, and WaveTrack::UpdateLocationsCache().

Referenced by DrawTrack().

1519 {
1520  auto &dc = context.dc;
1521 
1522  bool highlight = false;
1523  bool gripHit = false;
1524 #ifdef EXPERIMENTAL_TRACK_PANEL_HIGHLIGHTING
1525  auto target = dynamic_cast<TimeShiftHandle*>(context.target.get());
1526  gripHit = target && target->IsGripHit();
1527  highlight = target && target->GetTrack().get() == track;
1528 #endif
1529 
1530  const bool dB = !track->GetWaveformSettings().isLinear();
1531 
1533  selectedRegion, zoomInfo);
1534 
1535  for (const auto &clip: track->GetClips())
1536  DrawClipWaveform(context, track, clip.get(), rect, selectedRegion, zoomInfo,
1537  drawEnvelope, bigPoints,
1538  dB, muted);
1539 
1540  // Update cache for locations, e.g. cutlines and merge points
1541  track->UpdateLocationsCache();
1542 
1543 #ifdef EXPERIMENTAL_TRACK_PANEL_HIGHLIGHTING
1544  auto target2 = dynamic_cast<CutlineHandle*>(context.target.get());
1545 #endif
1546  for (const auto loc : track->GetCachedLocations()) {
1547  bool highlight = false;
1548 #ifdef EXPERIMENTAL_TRACK_PANEL_HIGHLIGHTING
1549  highlight =
1550  target2 && target2->GetTrack().get() == track &&
1551  target2->GetLocation() == loc;
1552 #endif
1553  const int xx = zoomInfo.TimeToPosition(loc.pos);
1554  if (xx >= 0 && xx < rect.width) {
1555  dc.SetPen( highlight ? AColor::uglyPen : *wxGREY_PEN );
1556  AColor::Line(dc, (int) (rect.x + xx - 1), rect.y, (int) (rect.x + xx - 1), rect.y + rect.height);
1557  if (loc.typ == WaveTrackLocation::locationCutLine) {
1558  dc.SetPen( highlight ? AColor::uglyPen : *wxRED_PEN );
1559  }
1560  else {
1561 #ifdef EXPERIMENTAL_DA
1562  // JKC Black does not show up enough.
1563  dc.SetPen(highlight ? AColor::uglyPen : *wxWHITE_PEN);
1564 #else
1565  dc.SetPen(highlight ? AColor::uglyPen : *wxBLACK_PEN);
1566 #endif
1567  }
1568  AColor::Line(dc, (int) (rect.x + xx), rect.y, (int) (rect.x + xx), rect.y + rect.height);
1569  dc.SetPen( highlight ? AColor::uglyPen : *wxGREY_PEN );
1570  AColor::Line(dc, (int) (rect.x + xx + 1), rect.y, (int) (rect.x + xx + 1), rect.y + rect.height);
1571  }
1572  }
1573 
1574  if (drawSliders) {
1575  DrawTimeSlider(dc, rect, true, highlight && gripHit); // directed right
1576  DrawTimeSlider(dc, rect, false, highlight && gripHit); // directed left
1577  }
1578 }
const std::vector< Location > & GetCachedLocations() const
Definition: WaveTrack.h:502
bool isLinear() const
void DrawTimeSlider(wxDC &dc, const wxRect &rect, bool rightwards, bool highlight)
const WaveformSettings & GetWaveformSettings() const
Definition: WaveTrack.cpp:738
void DrawClipWaveform(TrackPanelDrawingContext &context, const WaveTrack *track, const WaveClip *clip, const wxRect &rect, const SelectedRegion &selectedRegion, const ZoomInfo &zoomInfo, bool drawEnvelope, bool bigPoints, bool dB, bool muted)
bool IsGripHit() const
void UpdateLocationsCache() const
Definition: WaveTrack.cpp:2406
static wxPen uglyPen
Definition: AColor.h:147
static void DrawBackgroundWithSelection(wxDC *dc, const wxRect &rect, const Track *track, wxBrush &selBrush, wxBrush &unselBrush, const SelectedRegion &selectedRegion, const ZoomInfo &zoomInfo)
wxBrush blankSelectedBrush
Definition: TrackArtist.h:197
WaveClipHolders & GetClips()
Definition: WaveTrack.h:364
static void Line(wxDC &dc, wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2)
Definition: AColor.cpp:122
std::shared_ptr< WaveTrack > GetTrack()
Definition: CutlineHandle.h:46
wxBrush blankBrush
Definition: TrackArtist.h:190
void TrackArtist::DrawWaveformBackground ( wxDC &  dc,
int  leftOffset,
const wxRect &  rect,
const double  env[],
float  zoomMin,
float  zoomMax,
int  zeroLevelYCoordinate,
bool  dB,
float  dBRange,
double  t0,
double  t1,
const ZoomInfo zoomInfo,
bool  drawEnvelope,
bool  bIsSyncLockSelected,
bool  highlightEnvelope 
)
private

Definition at line 1072 of file TrackArtist.cpp.

References blankBrush, DrawSyncLockTiles(), GetWaveYPos(), AColor::Line(), min(), ZoomInfo::PositionToTime(), selectedBrush, ZoomInfo::TimeToPosition(), AColor::uglyBrush, and unselectedBrush.

Referenced by DrawClipWaveform().

1081 {
1082 
1083  // Visually (one vertical slice of the waveform background, on its side;
1084  // the "*" is the actual waveform background we're drawing
1085  //
1086  //1.0 0.0 -1.0
1087  // |--------------------------------|--------------------------------|
1088  // *************** ***************
1089  // | | | |
1090  // maxtop maxbot mintop minbot
1091 
1092  int h = rect.height;
1093  int halfHeight = wxMax(h / 2, 1);
1094  int maxtop, lmaxtop = 0;
1095  int mintop, lmintop = 0;
1096  int maxbot, lmaxbot = 0;
1097  int minbot, lminbot = 0;
1098  bool sel, lsel = false;
1099  int xx, lx = 0;
1100  int l, w;
1101 
1102  dc.SetPen(*wxTRANSPARENT_PEN);
1103  dc.SetBrush(blankBrush);
1104  dc.DrawRectangle(rect);
1105 
1106  double time = zoomInfo.PositionToTime(0, -leftOffset), nextTime;
1107  for (xx = 0; xx < rect.width; ++xx, time = nextTime) {
1108  nextTime = zoomInfo.PositionToTime(xx + 1, -leftOffset);
1109  // First we compute the truncated shape of the waveform background.
1110  // If drawEnvelope is true, then we compute the lower border of the
1111  // envelope.
1112 
1113  maxtop = GetWaveYPos(env[xx], zoomMin, zoomMax,
1114  h, dB, true, dBRange, true);
1115  maxbot = GetWaveYPos(env[xx], zoomMin, zoomMax,
1116  h, dB, false, dBRange, true);
1117 
1118  mintop = GetWaveYPos(-env[xx], zoomMin, zoomMax,
1119  h, dB, false, dBRange, true);
1120  minbot = GetWaveYPos(-env[xx], zoomMin, zoomMax,
1121  h, dB, true, dBRange, true);
1122 
1123  // Make sure it's odd so that a that max and min mirror each other
1124  mintop +=1;
1125  minbot +=1;
1126 
1127  if (!drawEnvelope || maxbot > mintop) {
1128  maxbot = halfHeight;
1129  mintop = halfHeight;
1130  }
1131 
1132  // We don't draw selection color for sync-lock selected tracks.
1133  sel = (t0 <= time && nextTime < t1) && !bIsSyncLockSelected;
1134 
1135  if (lmaxtop == maxtop &&
1136  lmintop == mintop &&
1137  lmaxbot == maxbot &&
1138  lminbot == minbot &&
1139  lsel == sel) {
1140  continue;
1141  }
1142 
1143  dc.SetBrush(lsel ? selectedBrush : unselectedBrush);
1144 
1145  l = rect.x + lx;
1146  w = xx - lx;
1147  if (lmaxbot < lmintop - 1) {
1148  dc.DrawRectangle(l, rect.y + lmaxtop, w, lmaxbot - lmaxtop);
1149  dc.DrawRectangle(l, rect.y + lmintop, w, lminbot - lmintop);
1150  }
1151  else {
1152  dc.DrawRectangle(l, rect.y + lmaxtop, w, lminbot - lmaxtop);
1153  }
1154 
1155  if (highlightEnvelope && lmaxbot < lmintop - 1) {
1156  dc.SetBrush( AColor::uglyBrush );
1157  dc.DrawRectangle(l, rect.y + lmaxbot, w, lmintop - lmaxbot);
1158  }
1159 
1160  lmaxtop = maxtop;
1161  lmintop = mintop;
1162  lmaxbot = maxbot;
1163  lminbot = minbot;
1164  lsel = sel;
1165  lx = xx;
1166  }
1167 
1168  dc.SetBrush(lsel ? selectedBrush : unselectedBrush);
1169  l = rect.x + lx;
1170  w = xx - lx;
1171  if (lmaxbot < lmintop - 1) {
1172  dc.DrawRectangle(l, rect.y + lmaxtop, w, lmaxbot - lmaxtop);
1173  dc.DrawRectangle(l, rect.y + lmintop, w, lminbot - lmintop);
1174  }
1175  else {
1176  dc.DrawRectangle(l, rect.y + lmaxtop, w, lminbot - lmaxtop);
1177  }
1178  if (highlightEnvelope && lmaxbot < lmintop - 1) {
1179  dc.SetBrush( AColor::uglyBrush );
1180  dc.DrawRectangle(l, rect.y + lmaxbot, w, lmintop - lmaxbot);
1181  }
1182 
1183  // If sync-lock selected, draw in linked graphics.
1184  if (bIsSyncLockSelected && t0 < t1) {
1185  const int begin = std::max(0, std::min(rect.width, (int)(zoomInfo.TimeToPosition(t0, -leftOffset))));
1186  const int end = std::max(0, std::min(rect.width, (int)(zoomInfo.TimeToPosition(t1, -leftOffset))));
1187  DrawSyncLockTiles(&dc, wxRect(rect.x + begin, rect.y, end - 1 - begin, rect.height));
1188  }
1189 
1190  //OK, the display bounds are between min and max, which
1191  //is spread across rect.height. Draw the line at the proper place.
1192  if (zeroLevelYCoordinate >= rect.GetTop() &&
1193  zeroLevelYCoordinate <= rect.GetBottom()) {
1194  dc.SetPen(*wxBLACK_PEN);
1195  AColor::Line(dc, rect.x, zeroLevelYCoordinate,
1196  rect.x + rect.width, zeroLevelYCoordinate);
1197  }
1198 }
static wxBrush uglyBrush
Definition: AColor.h:148
double PositionToTime(wxInt64 position, wxInt64 origin=0, bool ignoreFisheye=false) const
Definition: ViewInfo.cpp:49
wxBrush selectedBrush
Definition: TrackArtist.h:192
wxBrush unselectedBrush
Definition: TrackArtist.h:191
static void DrawSyncLockTiles(wxDC *dc, wxRect rect)
wxInt64 TimeToPosition(double time, wxInt64 origin=0, bool ignoreFisheye=false) const
STM: Converts a project time to screen x position.
Definition: ViewInfo.cpp:59
int min(int a, int b)
static void Line(wxDC &dc, wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2)
Definition: AColor.cpp:122
wxBrush blankBrush
Definition: TrackArtist.h:190
int GetWaveYPos(float value, float min, float max, int height, bool dB, bool outer, float dBr, bool clip)
void TrackArtist::SetBackgroundBrushes ( wxBrush  unselectedBrush,
wxBrush  selectedBrush,
wxPen  unselectedPen,
wxPen  selectedPen 
)
inline

Definition at line 80 of file TrackArtist.h.

Referenced by AudacityPrintout::OnPrintPage().

81  {
85  this->selectedPen = selectedPen;
86  }
wxBrush selectedBrush
Definition: TrackArtist.h:192
wxBrush unselectedBrush
Definition: TrackArtist.h:191
wxPen unselectedPen
Definition: TrackArtist.h:199
wxPen selectedPen
Definition: TrackArtist.h:200
void TrackArtist::SetColours ( int  iColorIndex)

Definition at line 287 of file TrackArtist.cpp.

References blankBrush, blankPen, blankSelectedBrush, blankSelectedPen, clippedPen, dragsampleBrush, muteClippedPen, muteRmsPen, muteSamplePen, odProgressDonePen, odProgressNotYetPen, rmsPen, sampleBrush, samplePen, selectedBrush, selectedPen, selsampleBrush, selsamplePen, ThemeBase::SetBrushColour(), ThemeBase::SetPenColour(), shadowPen, theTheme, unselectedBrush, and unselectedPen.

Referenced by DrawClipWaveform(), TrackArtist(), and UpdatePrefs().

288 {
289  theTheme.SetBrushColour( blankBrush, clrBlank );
290  theTheme.SetBrushColour( unselectedBrush, clrUnselected);
291  theTheme.SetBrushColour( selectedBrush, clrSelected);
292  theTheme.SetBrushColour( sampleBrush, clrSample);
293  theTheme.SetBrushColour( selsampleBrush, clrSelSample);
294  theTheme.SetBrushColour( dragsampleBrush, clrDragSample);
295  theTheme.SetBrushColour( blankSelectedBrush, clrBlankSelected);
296 
297  theTheme.SetPenColour( blankPen, clrBlank);
298  theTheme.SetPenColour( unselectedPen, clrUnselected);
299  theTheme.SetPenColour( selectedPen, clrSelected);
300  theTheme.SetPenColour( muteSamplePen, clrMuteSample);
301  theTheme.SetPenColour( odProgressDonePen, clrProgressDone);
302  theTheme.SetPenColour( odProgressNotYetPen, clrProgressNotYet);
303  theTheme.SetPenColour( shadowPen, clrShadow);
304  theTheme.SetPenColour( clippedPen, clrClipped);
305  theTheme.SetPenColour( muteClippedPen, clrMuteClipped);
306  theTheme.SetPenColour( blankSelectedPen,clrBlankSelected);
307 
308  theTheme.SetPenColour( selsamplePen, clrSelSample);
309  theTheme.SetPenColour( muteRmsPen, clrMuteRms);
310 
311  switch( iColorIndex %4 )
312  {
313  default:
314  case 0:
315  theTheme.SetPenColour( samplePen, clrSample);
316  theTheme.SetPenColour( rmsPen, clrRms);
317  break;
318  case 1: // RED
319  samplePen.SetColour( wxColor( 160,10,10 ) );
320  rmsPen.SetColour( wxColor( 230,80,80 ) );
321  break;
322  case 2: // GREEN
323  samplePen.SetColour( wxColor( 35,110,35 ) );
324  rmsPen.SetColour( wxColor( 75,200,75 ) );
325  break;
326  case 3: //BLACK
327  samplePen.SetColour( wxColor( 0,0,0 ) );
328  rmsPen.SetColour( wxColor( 100,100,100 ) );
329  break;
330 
331  }
332 }
wxPen muteClippedPen
Definition: TrackArtist.h:210
AUDACITY_DLL_API Theme theTheme
Definition: Theme.cpp:209
wxPen samplePen
Definition: TrackArtist.h:201
wxPen blankSelectedPen
Definition: TrackArtist.h:211
wxPen muteRmsPen
Definition: TrackArtist.h:203
wxBrush dragsampleBrush
Definition: TrackArtist.h:195
wxBrush selectedBrush
Definition: TrackArtist.h:192
wxBrush blankSelectedBrush
Definition: TrackArtist.h:197
wxBrush unselectedBrush
Definition: TrackArtist.h:191
void SetBrushColour(wxBrush &Brush, int iIndex)
Definition: Theme.cpp:1232
wxPen unselectedPen
Definition: TrackArtist.h:199
wxPen shadowPen
Definition: TrackArtist.h:208
wxPen odProgressDonePen
Definition: TrackArtist.h:207
wxPen blankPen
Definition: TrackArtist.h:198
wxPen selsamplePen
Definition: TrackArtist.h:204
wxPen odProgressNotYetPen
Definition: TrackArtist.h:206
wxPen selectedPen
Definition: TrackArtist.h:200
wxBrush sampleBrush
Definition: TrackArtist.h:193
wxPen rmsPen
Definition: TrackArtist.h:202
wxBrush blankBrush
Definition: TrackArtist.h:190
wxPen clippedPen
Definition: TrackArtist.h:209
wxPen muteSamplePen
Definition: TrackArtist.h:205
wxBrush selsampleBrush
Definition: TrackArtist.h:194
void SetPenColour(wxPen &Pen, int iIndex)
Definition: Theme.cpp:1238
void TrackArtist::SetMargins ( int  left,
int  top,
int  right,
int  bottom 
)

Definition at line 334 of file TrackArtist.cpp.

References mMarginBottom, mMarginLeft, mMarginRight, and mMarginTop.

335 {
336  mMarginLeft = left;
337  mMarginTop = top;
338  mMarginRight = right;
339  mMarginBottom = bottom;
340 }
int mMarginRight
Definition: TrackArtist.h:187
int mMarginBottom
Definition: TrackArtist.h:188
void TrackArtist::UpdatePrefs ( )

Definition at line 3311 of file TrackArtist.cpp.

References ENV_DB_KEY, gPrefs, mdBrange, mSampleDisplay, mShowClipping, TracksPrefs::SampleViewChoice(), and SetColours().

Referenced by TrackArtist().

3312 {
3313  mdBrange = gPrefs->Read(ENV_DB_KEY, mdBrange);
3314  mShowClipping = gPrefs->Read(wxT("/GUI/ShowClipping"), mShowClipping);
3316  SetColours(0);
3317 }
AudacityPrefs * gPrefs
Definition: Prefs.cpp:73
long mShowClipping
Definition: TrackArtist.h:181
#define ENV_DB_KEY
Definition: GUISettings.h:15
static WaveTrack::SampleDisplay SampleViewChoice()
int mSampleDisplay
Definition: TrackArtist.h:182
void SetColours(int iColorIndex)
float mdBrange
Definition: TrackArtist.h:180
void TrackArtist::UpdateVRuler ( const Track t,
wxRect &  rect 
)

Definition at line 694 of file TrackArtist.cpp.

References DB_TO_LINEAR(), WaveformSettings::dBRange, WaveTrack::GetDisplay(), WaveTrack::GetDisplayBounds(), TimeTrack::GetDisplayLog(), Track::GetKind(), WaveTrack::GetLastdBRange(), WaveTrack::GetLastScaleType(), TimeTrack::GetRangeLower(), TimeTrack::GetRangeUpper(), SpectrogramSettings::GetScale(), WaveTrack::GetSpectrogramSettings(), WaveTrack::GetSpectrumBounds(), WaveTrack::GetWaveformSettings(), Ruler::IntFormat, Track::Label, LINEAR_TO_DB, min(), Ruler::RealFormat, Ruler::RealLogFormat, NumberScale::Reversal(), WaveformSettings::scaleType, SpectrogramSettings::scaleType, WaveTrack::SetDisplayBounds(), WaveTrack::SetLastdBRange(), WaveTrack::SetLastScaleType(), WaveTrack::Spectrum, SpectrogramSettings::stBark, SpectrogramSettings::stErb, WaveformSettings::stLinear, SpectrogramSettings::stLinear, WaveformSettings::stLogarithmic, SpectrogramSettings::stLogarithmic, SpectrogramSettings::stMel, SpectrogramSettings::stPeriod, Track::Time, vruler, Track::vrulerSize, Track::Wave, and WaveTrack::Waveform.

695 {
696  // Label tracks do not have a vruler
697  if (t->GetKind() == Track::Label) {
698  return;
699  }
700 
701  // Time tracks
702  if (t->GetKind() == Track::Time) {
703  const TimeTrack *tt = (TimeTrack *)t;
704  float min, max;
705  min = tt->GetRangeLower() * 100.0;
706  max = tt->GetRangeUpper() * 100.0;
707 
708  vruler->SetDbMirrorValue( 0.0 );
709  vruler->SetBounds(rect.x, rect.y, rect.x + rect.width, rect.y + rect.height-1);
710  vruler->SetOrientation(wxVERTICAL);
711  vruler->SetRange(max, min);
713  vruler->SetUnits(wxT(""));
714  vruler->SetLabelEdges(false);
715  vruler->SetLog(tt->GetDisplayLog());
716  }
717 
718  // All waves have a ruler in the info panel
719  // The ruler needs a bevelled surround.
720  if (t->GetKind() == Track::Wave) {
721  const WaveTrack *wt = static_cast<const WaveTrack*>(t);
722  const float dBRange =
724 
725  const int display = wt->GetDisplay();
726 
727  if (display == WaveTrack::Waveform) {
728  WaveformSettings::ScaleType scaleType =
730 
731  if (scaleType == WaveformSettings::stLinear) {
732  // Waveform
733 
734  float min, max;
735  wt->GetDisplayBounds(&min, &max);
736  if (wt->GetLastScaleType() != scaleType &&
737  wt->GetLastScaleType() != -1)
738  {
739  // do a translation into the linear space
740  wt->SetLastScaleType();
741  wt->SetLastdBRange();
742  float sign = (min >= 0 ? 1 : -1);
743  if (min != 0.) {
744  min = DB_TO_LINEAR(fabs(min) * dBRange - dBRange);
745  if (min < 0.0)
746  min = 0.0;
747  min *= sign;
748  }
749  sign = (max >= 0 ? 1 : -1);
750 
751  if (max != 0.) {
752  max = DB_TO_LINEAR(fabs(max) * dBRange - dBRange);
753  if (max < 0.0)
754  max = 0.0;
755  max *= sign;
756  }
757  wt->SetDisplayBounds(min, max);
758  }
759 
760  vruler->SetDbMirrorValue( 0.0 );
761  vruler->SetBounds(rect.x, rect.y, rect.x + rect.width, rect.y + rect.height - 1);
762  vruler->SetOrientation(wxVERTICAL);
763  vruler->SetRange(max, min);
764  vruler->SetFormat(Ruler::RealFormat);
765  vruler->SetUnits(wxT(""));
766  vruler->SetLabelEdges(false);
767  vruler->SetLog(false);
768  }
769  else {
770  wxASSERT(scaleType == WaveformSettings::stLogarithmic);
772 
773  vruler->SetUnits(wxT(""));
774 
775  float min, max;
776  wt->GetDisplayBounds(&min, &max);
777  float lastdBRange;
778 
779  if (wt->GetLastScaleType() != scaleType &&
780  wt->GetLastScaleType() != -1)
781  {
782  // do a translation into the dB space
783  wt->SetLastScaleType();
784  wt->SetLastdBRange();
785  float sign = (min >= 0 ? 1 : -1);
786  if (min != 0.) {
787  min = (LINEAR_TO_DB(fabs(min)) + dBRange) / dBRange;
788  if (min < 0.0)
789  min = 0.0;
790  min *= sign;
791  }
792  sign = (max >= 0 ? 1 : -1);
793 
794  if (max != 0.) {
795  max = (LINEAR_TO_DB(fabs(max)) + dBRange) / dBRange;
796  if (max < 0.0)
797  max = 0.0;
798  max *= sign;
799  }
800  wt->SetDisplayBounds(min, max );
801  }
802  else if (dBRange != (lastdBRange = wt->GetLastdBRange())) {
803  wt->SetLastdBRange();
804  // Remap the max of the scale
805  float newMax = max;
806 
807 // This commented out code is problematic.
808 // min and max may be correct, and this code cause them to change.
809 #ifdef ONLY_LABEL_POSITIVE
810  const float sign = (max >= 0 ? 1 : -1);
811  if (max != 0.) {
812 
813 // Ugh, duplicating from TrackPanel.cpp
814 #define ZOOMLIMIT 0.001f
815 
816  const float extreme = LINEAR_TO_DB(2);
817  // recover dB value of max
818  const float dB = std::min(extreme, (float(fabs(max)) * lastdBRange - lastdBRange));
819  // find NEW scale position, but old max may get trimmed if the db limit rises
820  // Don't trim it to zero though, but leave max and limit distinct
821  newMax = sign * std::max(ZOOMLIMIT, (dBRange + dB) / dBRange);
822  // Adjust the min of the scale if we can,
823  // so the db Limit remains where it was on screen, but don't violate extremes
824  if (min != 0.)
825  min = std::max(-extreme, newMax * min / max);
826  }
827 #endif
828  wt->SetDisplayBounds(min, newMax );
829  }
830 
831 
832 // Old code was if ONLY_LABEL_POSITIVE were defined.
833 // it uses the +1 to 0 range only.
834 // the enabled code uses +1 to -1, and relies on set ticks labelling knowing about
835 // the dB scale.
836 #ifdef ONLY_LABEL_POSITIVE
837  if (max > 0) {
838 #endif
839  int top = 0;
840  float topval = 0;
841  int bot = rect.height;
842  float botval = -dBRange;
843 
844 #ifdef ONLY_LABEL_POSITIVE
845  if (min < 0) {
846  bot = top + (int)((max / (max - min))*(bot - top));
847  min = 0;
848  }
849 
850  if (max > 1) {
851  top += (int)((max - 1) / (max - min) * (bot - top));
852  max = 1;
853  }
854 
855  if (max < 1 && max > 0)
856  topval = -((1 - max) * dBRange);
857 
858  if (min > 0) {
859  botval = -((1 - min) * dBRange);
860  }
861 #else
862  topval = -((1 - max) * dBRange);
863  botval = -((1 - min) * dBRange);
864  vruler->SetDbMirrorValue( dBRange );
865 #endif
866  vruler->SetBounds(rect.x, rect.y + top, rect.x + rect.width, rect.y + bot - 1);
867  vruler->SetOrientation(wxVERTICAL);
868  vruler->SetRange(topval, botval);
869 #ifdef ONLY_LABEL_POSITIVE
870  }
871  else
872  vruler->SetBounds(0.0, 0.0, 0.0, 0.0); // A.C.H I couldn't find a way to just disable it?
873 #endif
874  vruler->SetFormat(Ruler::RealLogFormat);
875  vruler->SetLabelEdges(true);
876  vruler->SetLog(false);
877  }
878  }
879  else {
880  wxASSERT(display == WaveTrack::Spectrum);
881  const SpectrogramSettings &settings = wt->GetSpectrogramSettings();
882  float minFreq, maxFreq;
883  wt->GetSpectrumBounds(&minFreq, &maxFreq);
884  vruler->SetDbMirrorValue( 0.0 );
885 
886  switch (settings.scaleType) {
887  default:
888  wxASSERT(false);
890  {
891  // Spectrum
892 
893  if (rect.height < 60)
894  return;
895 
896  /*
897  draw the ruler
898  we will use Hz if maxFreq is < 2000, otherwise we represent kHz,
899  and append to the numbers a "k"
900  */
901  vruler->SetBounds(rect.x, rect.y, rect.x + rect.width, rect.y + rect.height - 1);
902  vruler->SetOrientation(wxVERTICAL);
903  vruler->SetFormat(Ruler::RealFormat);
904  vruler->SetLabelEdges(true);
905  // use kHz in scale, if appropriate
906  if (maxFreq >= 2000) {
907  vruler->SetRange((maxFreq / 1000.), (minFreq / 1000.));
908  vruler->SetUnits(wxT("k"));
909  }
910  else {
911  // use Hz
912  vruler->SetRange((int)(maxFreq), (int)(minFreq));
913  vruler->SetUnits(wxT(""));
914  }
915  vruler->SetLog(false);
916  }
917  break;
923  {
924  // SpectrumLog
925 
926  if (rect.height < 10)
927  return;
928 
929  /*
930  draw the ruler
931  we will use Hz if maxFreq is < 2000, otherwise we represent kHz,
932  and append to the numbers a "k"
933  */
934  vruler->SetBounds(rect.x, rect.y, rect.x + rect.width, rect.y + rect.height - 1);
935  vruler->SetOrientation(wxVERTICAL);
936  vruler->SetFormat(Ruler::IntFormat);
937  vruler->SetLabelEdges(true);
938  vruler->SetRange(maxFreq, minFreq);
939  vruler->SetUnits(wxT(""));
940  vruler->SetLog(true);
941  NumberScale scale(
942  wt->GetSpectrogramSettings().GetScale( minFreq, maxFreq )
943  .Reversal() );
944  vruler->SetNumberScale(&scale);
945  }
946  break;
947  }
948  }
949  }
950 
951 #ifdef USE_MIDI
952  // The note track isn't drawing a ruler at all!
953  // But it needs to!
954  else if (t->GetKind() == Track::Note) {
955  vruler->SetBounds(rect.x, rect.y, rect.x + 1, rect.y + rect.height-1);
956  vruler->SetOrientation(wxVERTICAL);
957  }
958 #endif // USE_MIDI
959 
960  vruler->GetMaxSize(&t->vrulerSize.x, &t->vrulerSize.y);
961 }
bool GetDisplayLog() const
Definition: TimeTrack.h:133
std::unique_ptr< Ruler > vruler
Definition: TrackArtist.h:213
Spectrogram settings, either for one track or as defaults.
const WaveformSettings & GetWaveformSettings() const
Definition: WaveTrack.cpp:738
void GetSpectrumBounds(float *min, float *max) const
Definition: WaveTrack.cpp:337
double GetRangeLower() const
Definition: TimeTrack.h:127
void SetDisplayBounds(float min, float max) const
Definition: WaveTrack.cpp:331
int GetLastdBRange() const
Definition: WaveTrack.h:590
NumberScale Reversal() const
Definition: NumberScale.h:83
const SpectrogramSettings & GetSpectrogramSettings() const
Definition: WaveTrack.cpp:690
virtual int GetKind() const
Definition: Track.h:329
NumberScale GetScale(float minFreq, float maxFreq) const
void GetDisplayBounds(float *min, float *max) const
Definition: WaveTrack.cpp:325
A kind of Track used to 'warp time'.
Definition: TimeTrack.h:29
double GetRangeUpper() const
Definition: TimeTrack.h:128
A Track that contains audio waveform data.
Definition: WaveTrack.h:60
int min(int a, int b)
int GetLastScaleType() const
Definition: WaveTrack.h:587
#define LINEAR_TO_DB(x)
Definition: Audacity.h:217
void SetLastScaleType() const
Definition: WaveTrack.cpp:315
WaveTrackDisplay GetDisplay() const
Definition: WaveTrack.h:593
const double MIN_Threshold_Linear DB_TO_LINEAR(MIN_Threshold_dB)
wxSize vrulerSize
Definition: Track.h:175
void SetLastdBRange() const
Definition: WaveTrack.cpp:320

Member Data Documentation

wxBrush TrackArtist::blankBrush
private

Definition at line 190 of file TrackArtist.h.

Referenced by DrawSpectrum(), DrawWaveform(), DrawWaveformBackground(), and SetColours().

wxPen TrackArtist::blankPen
private

Definition at line 198 of file TrackArtist.h.

Referenced by SetColours().

wxBrush TrackArtist::blankSelectedBrush
private

Definition at line 197 of file TrackArtist.h.

Referenced by DrawSpectrum(), DrawWaveform(), and SetColours().

wxPen TrackArtist::blankSelectedPen
private

Definition at line 211 of file TrackArtist.h.

Referenced by SetColours().

wxPen TrackArtist::clippedPen
private

Definition at line 209 of file TrackArtist.h.

Referenced by DrawIndividualSamples(), DrawMinMaxRMS(), and SetColours().

wxBrush TrackArtist::dragsampleBrush
private

Definition at line 195 of file TrackArtist.h.

Referenced by DrawIndividualSamples(), and SetColours().

bool TrackArtist::mbShowTrackNameInWaveform
private

Definition at line 183 of file TrackArtist.h.

Referenced by DrawTrack(), and DrawTracks().

float TrackArtist::mdBrange
private

Definition at line 180 of file TrackArtist.h.

Referenced by DrawTimeTrack(), TrackArtist(), and UpdatePrefs().

int TrackArtist::mMarginBottom
private

Definition at line 188 of file TrackArtist.h.

Referenced by DrawTracks(), SetMargins(), and TrackArtist().

int TrackArtist::mMarginLeft
private

Definition at line 185 of file TrackArtist.h.

Referenced by DrawTracks(), SetMargins(), and TrackArtist().

int TrackArtist::mMarginRight
private

Definition at line 187 of file TrackArtist.h.

Referenced by DrawTracks(), SetMargins(), and TrackArtist().

int TrackArtist::mMarginTop
private

Definition at line 186 of file TrackArtist.h.

Referenced by DrawTracks(), SetMargins(), and TrackArtist().

int TrackArtist::mSampleDisplay
private

Definition at line 182 of file TrackArtist.h.

Referenced by DrawIndividualSamples(), TrackArtist(), and UpdatePrefs().

long TrackArtist::mShowClipping
private

Definition at line 181 of file TrackArtist.h.

Referenced by DrawIndividualSamples(), DrawMinMaxRMS(), TrackArtist(), and UpdatePrefs().

wxPen TrackArtist::muteClippedPen
private

Definition at line 210 of file TrackArtist.h.

Referenced by DrawIndividualSamples(), DrawMinMaxRMS(), and SetColours().

wxPen TrackArtist::muteRmsPen
private

Definition at line 203 of file TrackArtist.h.

Referenced by DrawMinMaxRMS(), and SetColours().

wxBrush TrackArtist::muteSampleBrush
private

Definition at line 196 of file TrackArtist.h.

wxPen TrackArtist::muteSamplePen
private

Definition at line 205 of file TrackArtist.h.

Referenced by DrawIndividualSamples(), DrawMinMaxRMS(), and SetColours().

wxPen TrackArtist::odProgressDonePen
private

Definition at line 207 of file TrackArtist.h.

Referenced by SetColours().

wxPen TrackArtist::odProgressNotYetPen
private

Definition at line 206 of file TrackArtist.h.

Referenced by SetColours().

wxPen TrackArtist::rmsPen
private

Definition at line 202 of file TrackArtist.h.

Referenced by DrawMinMaxRMS(), and SetColours().

wxBrush TrackArtist::sampleBrush
private

Definition at line 193 of file TrackArtist.h.

Referenced by DrawIndividualSamples(), and SetColours().

wxPen TrackArtist::samplePen
private

Definition at line 201 of file TrackArtist.h.

Referenced by DrawIndividualSamples(), DrawMinMaxRMS(), and SetColours().

wxBrush TrackArtist::selectedBrush
private

Definition at line 192 of file TrackArtist.h.

Referenced by DrawWaveformBackground(), and SetColours().

wxPen TrackArtist::selectedPen
private

Definition at line 200 of file TrackArtist.h.

Referenced by SetColours().

wxBrush TrackArtist::selsampleBrush
private

Definition at line 194 of file TrackArtist.h.

Referenced by SetColours().

wxPen TrackArtist::selsamplePen
private

Definition at line 204 of file TrackArtist.h.

Referenced by SetColours().

wxPen TrackArtist::shadowPen
private

Definition at line 208 of file TrackArtist.h.

Referenced by SetColours().

wxBrush TrackArtist::unselectedBrush
private

Definition at line 191 of file TrackArtist.h.

Referenced by DrawWaveformBackground(), and SetColours().

wxPen TrackArtist::unselectedPen
private

Definition at line 199 of file TrackArtist.h.

Referenced by SetColours().

std::unique_ptr<Ruler> TrackArtist::vruler
private

Definition at line 213 of file TrackArtist.h.

Referenced by TrackArtist(), and UpdateVRuler().


The documentation for this class was generated from the following files: