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 266 of file TrackArtist.cpp.

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

267 {
268  mMarginLeft = 0;
269  mMarginTop = 0;
270  mMarginRight = 0;
271  mMarginBottom = 0;
272 
274  mShowClipping = false;
275  mSampleDisplay = 1;// Stem plots by default.
276  UpdatePrefs();
277 
278  SetColours(0);
279  vruler = std::make_unique<Ruler>();
280 }
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 282 of file TrackArtist.cpp.

283 {
284 }

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 3403 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().

3406 {
3407  //MM: Draw background. We should optimize that a bit more.
3408  //AWD: "+ 1.5" and "+ 2.5" throughout match code in
3409  //AdornedRulerPanel::DoDrawSelection() and make selection line up with ruler.
3410  //I don't know if/why this is correct.
3411 
3412  const double sel0 = selectedRegion.t0();
3413  const double sel1 = selectedRegion.t1();
3414 
3415  dc->SetPen(*wxTRANSPARENT_PEN);
3416  if (track->GetSelected() || track->IsSyncLockSelected())
3417  {
3418  // Rectangles before, within, after the selction
3419  wxRect before = rect;
3420  wxRect within = rect;
3421  wxRect after = rect;
3422 
3423  before.width = (int)(zoomInfo.TimeToPosition(sel0) + 2);
3424  if (before.GetRight() > rect.GetRight()) {
3425  before.width = rect.width;
3426  }
3427 
3428  if (before.width > 0) {
3429  dc->SetBrush(unselBrush);
3430  dc->DrawRectangle(before);
3431 
3432  within.x = 1 + before.GetRight();
3433  }
3434  within.width = rect.x + (int)(zoomInfo.TimeToPosition(sel1) + 2) - within.x;
3435 
3436  if (within.GetRight() > rect.GetRight()) {
3437  within.width = 1 + rect.GetRight() - within.x;
3438  }
3439 
3440  if (within.width > 0) {
3441  if (track->GetSelected()) {
3442  dc->SetBrush(selBrush);
3443  dc->DrawRectangle(within);
3444  }
3445  else {
3446  // Per condition above, track must be sync-lock selected
3447  dc->SetBrush(unselBrush);
3448  dc->DrawRectangle(within);
3449  DrawSyncLockTiles(dc, within);
3450  }
3451 
3452  after.x = 1 + within.GetRight();
3453  }
3454  else {
3455  // `within` not drawn; start where it would have gone
3456  after.x = within.x;
3457  }
3458 
3459  after.width = 1 + rect.GetRight() - after.x;
3460  if (after.width > 0) {
3461  dc->SetBrush(unselBrush);
3462  dc->DrawRectangle(after);
3463  }
3464  }
3465  else
3466  {
3467  // Track not selected; just draw background
3468  dc->SetBrush(unselBrush);
3469  dc->DrawRectangle(rect);
3470  }
3471 }
double t0() const
bool GetSelected() const
Definition: Track.h:217
bool IsSyncLockSelected() const
Definition: Track.cpp:232
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 2166 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().

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

1771 {
1772  auto &dc = context.dc;
1773 #ifdef PROFILE_WAVEFORM
1774  Profiler profiler;
1775 #endif
1776 
1777  bool highlightEnvelope = false;
1778 #ifdef EXPERIMENTAL_TRACK_PANEL_HIGHLIGHTING
1779  auto target = dynamic_cast<EnvelopeHandle*>(context.target.get());
1780  highlightEnvelope = target && target->GetEnvelope() == clip->GetEnvelope();
1781 #endif
1782 
1783  const ClipParameters params(false, track, clip, rect, selectedRegion, zoomInfo);
1784  const wxRect &hiddenMid = params.hiddenMid;
1785  // The "hiddenMid" rect contains the part of the display actually
1786  // containing the waveform, as it appears without the fisheye. If it's empty, we're done.
1787  if (hiddenMid.width <= 0) {
1788  return;
1789  }
1790 
1791  const double &t0 = params.t0;
1792  const double &tOffset = params.tOffset;
1793  const double &h = params.h;
1794  const double &tpre = params.tpre;
1795  const double &tpost = params.tpost;
1796  const double &t1 = params.t1;
1797  const double &averagePixelsPerSample = params.averagePixelsPerSample;
1798  const double &rate = params.rate;
1799  double leftOffset = params.leftOffset;
1800  const wxRect &mid = params.mid;
1801 
1802  const float dBRange = track->GetWaveformSettings().dBRange;
1803 
1804  dc.SetPen(*wxTRANSPARENT_PEN);
1805  int iColorIndex = clip->GetColourIndex();
1806  SetColours( iColorIndex );
1807 
1808  // If we get to this point, the clip is actually visible on the
1809  // screen, so remember the display rectangle.
1810  clip->SetDisplayRect(hiddenMid);
1811 
1812  // The bounds (controlled by vertical zooming; -1.0...1.0
1813  // by default)
1814  float zoomMin, zoomMax;
1815  track->GetDisplayBounds(&zoomMin, &zoomMax);
1816 
1817  std::vector<double> vEnv(mid.width);
1818  double *const env = &vEnv[0];
1819  clip->GetEnvelope()->GetValues
1820  ( tOffset,
1821 
1822  // PRL: change back to make envelope evaluate only at sample times
1823  // and then interpolate the display
1824  0, // 1.0 / rate,
1825 
1826  env, mid.width, leftOffset, zoomInfo );
1827 
1828  // Draw the background of the track, outlining the shape of
1829  // the envelope and using a colored pen for the selected
1830  // part of the waveform
1831  {
1832  double t0, t1;
1833  if (track->GetSelected() || track->IsSyncLockSelected()) {
1834  t0 = track->LongSamplesToTime(track->TimeToLongSamples(selectedRegion.t0())),
1835  t1 = track->LongSamplesToTime(track->TimeToLongSamples(selectedRegion.t1()));
1836  }
1837  else
1838  t0 = t1 = 0.0;
1839  DrawWaveformBackground(dc, leftOffset, mid,
1840  env,
1841  zoomMin, zoomMax,
1842  track->ZeroLevelYCoordinate(mid),
1843  dB, dBRange,
1844  t0, t1, zoomInfo, drawEnvelope,
1845  !track->GetSelected(), highlightEnvelope);
1846  }
1847 
1848  WaveDisplay display(hiddenMid.width);
1849  bool isLoadingOD = false;//true if loading on demand block in sequence.
1850 
1851  const double pps =
1852  averagePixelsPerSample * rate;
1853 
1854  // For each portion separately, we will decide to draw
1855  // it as min/max/rms or as individual samples.
1856  std::vector<WavePortion> portions;
1857  FindWavePortions(portions, rect, zoomInfo, params);
1858  const unsigned nPortions = portions.size();
1859 
1860  // Require at least 1/2 pixel per sample for drawing individual samples.
1861  const double threshold1 = 0.5 * rate;
1862  // Require at least 3 pixels per sample for drawing the draggable points.
1863  const double threshold2 = 3 * rate;
1864 
1865  {
1866  bool showIndividualSamples = false;
1867  for (unsigned ii = 0; !showIndividualSamples && ii < nPortions; ++ii) {
1868  const WavePortion &portion = portions[ii];
1869  showIndividualSamples =
1870  !portion.inFisheye && portion.averageZoom > threshold1;
1871  }
1872 
1873  if (!showIndividualSamples) {
1874  // The WaveClip class handles the details of computing the shape
1875  // of the waveform. The only way GetWaveDisplay will fail is if
1876  // there's a serious error, like some of the waveform data can't
1877  // be loaded. So if the function returns false, we can just exit.
1878 
1879  // Note that we compute the full width display even if there is a
1880  // fisheye hiding part of it, because of the caching. If the
1881  // fisheye moves over the background, there is then less to do when
1882  // redrawing.
1883 
1884  if (!clip->GetWaveDisplay(display,
1885  t0, pps, isLoadingOD))
1886  return;
1887  }
1888  }
1889 
1890  for (unsigned ii = 0; ii < nPortions; ++ii) {
1891  WavePortion &portion = portions[ii];
1892  const bool showIndividualSamples = portion.averageZoom > threshold1;
1893  const bool showPoints = portion.averageZoom > threshold2;
1894  wxRect& rect = portion.rect;
1895  rect.Intersect(mid);
1896  wxASSERT(rect.width >= 0);
1897 
1898  float *useMin = 0, *useMax = 0, *useRms = 0;
1899  int *useBl = 0;
1900  WaveDisplay fisheyeDisplay(rect.width);
1901  int skipped = 0, skippedLeft = 0, skippedRight = 0;
1902  if (portion.inFisheye) {
1903  if (!showIndividualSamples) {
1904  fisheyeDisplay.Allocate();
1905  const auto numSamples = clip->GetNumSamples();
1906  // Get wave display data for different magnification
1907  int jj = 0;
1908  for (; jj < rect.width; ++jj) {
1909  const double time =
1910  zoomInfo.PositionToTime(jj, -leftOffset) - tOffset;
1911  const auto sample = (sampleCount)floor(time * rate + 0.5);
1912  if (sample < 0) {
1913  ++rect.x;
1914  ++skippedLeft;
1915  continue;
1916  }
1917  if (sample >= numSamples)
1918  break;
1919  fisheyeDisplay.where[jj - skippedLeft] = sample;
1920  }
1921 
1922  skippedRight = rect.width - jj;
1923  skipped = skippedRight + skippedLeft;
1924  rect.width -= skipped;
1925 
1926  // where needs a sentinel
1927  if (jj > 0)
1928  fisheyeDisplay.where[jj - skippedLeft] =
1929  1 + fisheyeDisplay.where[jj - skippedLeft - 1];
1930  fisheyeDisplay.width -= skipped;
1931  // Get a wave display for the fisheye, uncached.
1932  if (rect.width > 0)
1933  if (!clip->GetWaveDisplay(
1934  fisheyeDisplay, t0, -1.0, // ignored
1935  isLoadingOD))
1936  continue; // serious error. just don't draw??
1937  useMin = fisheyeDisplay.min;
1938  useMax = fisheyeDisplay.max;
1939  useRms = fisheyeDisplay.rms;
1940  useBl = fisheyeDisplay.bl;
1941  }
1942  }
1943  else {
1944  const int pos = leftOffset - params.hiddenLeftOffset;
1945  useMin = display.min + pos;
1946  useMax = display.max + pos;
1947  useRms = display.rms + pos;
1948  useBl = display.bl + pos;
1949  }
1950 
1951  leftOffset += skippedLeft;
1952 
1953  if (rect.width > 0) {
1954  if (!showIndividualSamples) {
1955  std::vector<double> vEnv2(rect.width);
1956  double *const env2 = &vEnv2[0];
1957  clip->GetEnvelope()->GetValues
1958  ( tOffset,
1959 
1960  // PRL: change back to make envelope evaluate only at sample times
1961  // and then interpolate the display
1962  0, // 1.0 / rate,
1963 
1964  env2, rect.width, leftOffset, zoomInfo );
1965  DrawMinMaxRMS(dc, rect, env2,
1966  zoomMin, zoomMax,
1967  dB, dBRange,
1968  useMin, useMax, useRms, useBl,
1969  isLoadingOD, muted);
1970  }
1971  else {
1972  bool highlight = false;
1973 #ifdef EXPERIMENTAL_TRACK_PANEL_HIGHLIGHTING
1974  auto target = dynamic_cast<SampleHandle*>(context.target.get());
1975  highlight = target && target->GetTrack().get() == track;
1976 #endif
1977  DrawIndividualSamples(dc, leftOffset, rect, zoomMin, zoomMax,
1978  dB, dBRange,
1979  clip, zoomInfo,
1980  bigPoints, showPoints, muted, highlight);
1981  }
1982  }
1983 
1984  leftOffset += rect.width + skippedRight;
1985  }
1986 
1987  if (drawEnvelope) {
1988  DrawEnvelope(dc, mid, env, zoomMin, zoomMax, dB, dBRange, highlightEnvelope);
1989  clip->GetEnvelope()->DrawPoints
1990  (context, rect, zoomInfo, dB, dBRange, zoomMin, zoomMax, true);
1991  }
1992 
1993  // Draw arrows on the left side if the track extends to the left of the
1994  // beginning of time. :)
1995  if (h == 0.0 && tOffset < 0.0) {
1997  }
1998 
1999  // Draw clip edges
2000  dc.SetPen(*wxGREY_PEN);
2001  if (tpre < 0) {
2002  AColor::Line(dc,
2003  mid.x - 1, mid.y,
2004  mid.x - 1, mid.y + rect.height);
2005  }
2006  if (tpost > t1) {
2007  AColor::Line(dc,
2008  mid.x + mid.width, mid.y,
2009  mid.x + mid.width, mid.y + rect.height);
2010  }
2011 }
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:386
sampleCount GetNumSamples() const
Definition: WaveClip.cpp:448
void DrawNegativeOffsetTrackArrows(wxDC &dc, const wxRect &rect)
bool GetSelected() const
Definition: Track.h:217
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:715
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:232
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:324
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:1822
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:1827
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 1413 of file TrackArtist.cpp.

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

Referenced by DrawClipWaveform().

1416 {
1417  int h = rect.height;
1418 
1419  auto &pen = highlight ? AColor::uglyPen : AColor::envelopePen;
1420  dc.SetPen( pen );
1421 
1422  for (int x0 = 0; x0 < rect.width; ++x0) {
1423  int cenvTop = GetWaveYPos(env[x0], zoomMin, zoomMax,
1424  h, dB, true, dBRange, true);
1425 
1426  int cenvBot = GetWaveYPos(-env[x0], zoomMin, zoomMax,
1427  h, dB, true, dBRange, true);
1428 
1429  int envTop = GetWaveYPos(env[x0], zoomMin, zoomMax,
1430  h, dB, true, dBRange, false);
1431 
1432  int envBot = GetWaveYPos(-env[x0], zoomMin, zoomMax,
1433  h, dB, true, dBRange, false);
1434 
1435  // Make the collision at zero actually look solid
1436  if (cenvBot - cenvTop < 9) {
1437  int value = (int)((zoomMax / (zoomMax - zoomMin)) * h);
1438  cenvTop = value - 4;
1439  cenvBot = value + 4;
1440  }
1441 
1442  DrawEnvLine(dc, rect, x0, envTop, cenvTop, true);
1443  DrawEnvLine(dc, rect, x0, envBot, cenvBot, false);
1444  }
1445 }
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 1447 of file TrackArtist.cpp.

References AColor::Line().

Referenced by DrawEnvelope().

1448 {
1449  int xx = rect.x + x0;
1450  int yy = rect.y + cy;
1451 
1452  if (y0 < 0) {
1453  if (x0 % 4 != 3) {
1454  AColor::Line(dc, xx, yy, xx, yy + 3);
1455  }
1456  }
1457  else if (y0 > rect.height) {
1458  if (x0 % 4 != 3) {
1459  AColor::Line(dc, xx, yy - 3, xx, yy);
1460  }
1461  }
1462  else {
1463  if (top) {
1464  AColor::Line(dc, xx, yy, xx, yy + 3);
1465  }
1466  else {
1467  AColor::Line(dc, xx, yy - 3, xx, yy);
1468  }
1469  }
1470 }
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 1300 of file TrackArtist.cpp.

References clippedPen, dragsampleBrush, 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().

1307 {
1308  const double toffset = clip->GetOffset();
1309  double rate = clip->GetRate();
1310  const double t0 = std::max(0.0, zoomInfo.PositionToTime(0, -leftOffset) - toffset);
1311  const auto s0 = sampleCount(floor(t0 * rate));
1312  const auto snSamples = clip->GetNumSamples();
1313  if (s0 > snSamples)
1314  return;
1315 
1316  const double t1 = zoomInfo.PositionToTime(rect.width - 1, -leftOffset) - toffset;
1317  const auto s1 = sampleCount(ceil(t1 * rate));
1318 
1319  // Assume size_t will not overflow, else we wouldn't be here drawing the
1320  // few individual samples
1321  auto slen = std::min(snSamples - s0, s1 - s0 + 1).as_size_t();
1322 
1323  if (slen <= 0)
1324  return;
1325 
1326  Floats buffer{ size_t(slen) };
1327  clip->GetSamples((samplePtr)buffer.get(), floatSample, s0, slen,
1328  // Suppress exceptions in this drawing operation:
1329  false);
1330 
1331  ArrayOf<int> xpos{ size_t(slen) };
1332  ArrayOf<int> ypos{ size_t(slen) };
1333  ArrayOf<int> clipped;
1334  int clipcnt = 0;
1335 
1336  if (mShowClipping)
1337  clipped.reinit( size_t(slen) );
1338 
1339  auto &pen = highlight ? AColor::uglyPen : muted ? muteSamplePen : samplePen;
1340  dc.SetPen( pen );
1341 
1342  for (decltype(slen) s = 0; s < slen; s++) {
1343  const double time = toffset + (s + s0).as_double() / rate;
1344  const int xx = // An offset into the rectangle rect
1345  std::max(-10000, std::min(10000,
1346  (int)(zoomInfo.TimeToPosition(time, -leftOffset))));
1347  xpos[s] = xx;
1348 
1349  // Calculate sample as it would be rendered, so quantize time
1350  double value =
1351  clip->GetEnvelope()->GetValue( time, 1.0 / clip->GetRate() );
1352  const double tt = buffer[s] * value;
1353 
1354  if (clipped && mShowClipping && ((tt <= -MAX_AUDIO) || (tt >= MAX_AUDIO)))
1355  clipped[clipcnt++] = xx;
1356  ypos[s] =
1357  std::max(-1,
1358  std::min(rect.height,
1359  GetWaveYPos(tt, zoomMin, zoomMax,
1360  rect.height, dB, true, dBRange, false)));
1361  }
1362 
1363 
1364  if (showPoints) {
1365  // Draw points where spacing is enough
1366  const int tickSize = bigPoints ? 4 : 3;// Bigger ellipses when draggable.
1367  wxRect pr;
1368  pr.width = tickSize;
1369  pr.height = tickSize;
1370  //different colour when draggable.
1371  auto &brush = highlight
1373  : bigPoints ? dragsampleBrush : sampleBrush;
1374  dc.SetBrush( brush );
1375  for (decltype(slen) s = 0; s < slen; s++) {
1376  if (ypos[s] >= 0 && ypos[s] < rect.height) {
1377  pr.x = rect.x + xpos[s] - tickSize/2;
1378  pr.y = rect.y + ypos[s] - tickSize/2;
1379  dc.DrawEllipse(pr);
1380  }
1381  }
1382  }
1383 
1384  if (showPoints && (mSampleDisplay == (int) WaveTrack::StemPlot)) {
1385  // Draw vertical lines
1386  int yZero = GetWaveYPos(0.0, zoomMin, zoomMax, rect.height, dB, true, dBRange, false);
1387  yZero = rect.y + std::max(-1, std::min(rect.height, yZero));
1388  for (decltype(slen) s = 0; s < slen; s++) {
1389  AColor::Line(dc,
1390  rect.x + xpos[s], rect.y + ypos[s],
1391  rect.x + xpos[s], yZero);
1392  }
1393  }
1394  else {
1395  // Connect samples with straight lines
1396  for (decltype(slen) s = 0; s < slen - 1; s++) {
1397  AColor::Line(dc,
1398  rect.x + xpos[s], rect.y + ypos[s],
1399  rect.x + xpos[s + 1], rect.y + ypos[s + 1]);
1400  }
1401  }
1402 
1403  // Draw clipping
1404  if (clipcnt) {
1405  dc.SetPen(muted ? muteClippedPen : clippedPen);
1406  while (--clipcnt >= 0) {
1407  auto s = clipped[clipcnt];
1408  AColor::Line(dc, rect.x + s, rect.y, rect.x + s, rect.y + rect.height);
1409  }
1410  }
1411 }
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:499
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
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:212
void TrackArtist::DrawLabelTrack ( TrackPanelDrawingContext context,
const LabelTrack track,
const wxRect &  rect,
const SelectedRegion selectedRegion,
const ZoomInfo zoomInfo 
)
private

Definition at line 3241 of file TrackArtist.cpp.

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

Referenced by DrawTrack().

3246 {
3247  double sel0 = selectedRegion.t0();
3248  double sel1 = selectedRegion.t1();
3249 
3250  if (!track->GetSelected() && !track->IsSyncLockSelected())
3251  sel0 = sel1 = 0.0;
3252 
3253  track->Draw(context, rect, SelectedRegion(sel0, sel1), zoomInfo);
3254 }
double t0() const
bool GetSelected() const
Definition: Track.h:217
void Draw(TrackPanelDrawingContext &context, const wxRect &r, const SelectedRegion &selectedRegion, const ZoomInfo &zoomInfo) const
Definition: LabelTrack.cpp:784
bool IsSyncLockSelected() const
Definition: Track.cpp:232
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 1165 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().

1170 {
1171  // Display a line representing the
1172  // min and max of the samples in this region
1173  int lasth1 = std::numeric_limits<int>::max();
1174  int lasth2 = std::numeric_limits<int>::min();
1175  int h1;
1176  int h2;
1177  ArrayOf<int> r1{ size_t(rect.width) };
1178  ArrayOf<int> r2{ size_t(rect.width) };
1179  ArrayOf<int> clipped;
1180  int clipcnt = 0;
1181 
1182  if (mShowClipping) {
1183  clipped.reinit( size_t(rect.width) );
1184  }
1185 
1186  long pixAnimOffset = (long)fabs((double)(wxDateTime::Now().GetTicks() * -10)) +
1187  wxDateTime::Now().GetMillisecond() / 100; //10 pixels a second
1188 
1189  bool drawStripes = true;
1190  bool drawWaveform = true;
1191 
1192  dc.SetPen(muted ? muteSamplePen : samplePen);
1193  for (int x0 = 0; x0 < rect.width; ++x0) {
1194  int xx = rect.x + x0;
1195  double v;
1196  v = min[x0] * env[x0];
1197  if (clipped && mShowClipping && (v <= -MAX_AUDIO))
1198  {
1199  if (clipcnt == 0 || clipped[clipcnt - 1] != xx) {
1200  clipped[clipcnt++] = xx;
1201  }
1202  }
1203  h1 = GetWaveYPos(v, zoomMin, zoomMax,
1204  rect.height, dB, true, dBRange, true);
1205 
1206  v = max[x0] * env[x0];
1207  if (clipped && mShowClipping && (v >= MAX_AUDIO))
1208  {
1209  if (clipcnt == 0 || clipped[clipcnt - 1] != xx) {
1210  clipped[clipcnt++] = xx;
1211  }
1212  }
1213  h2 = GetWaveYPos(v, zoomMin, zoomMax,
1214  rect.height, dB, true, dBRange, true);
1215 
1216  // JKC: This adjustment to h1 and h2 ensures that the drawn
1217  // waveform is continuous.
1218  if (x0 > 0) {
1219  if (h1 < lasth2) {
1220  h1 = lasth2 - 1;
1221  }
1222  if (h2 > lasth1) {
1223  h2 = lasth1 + 1;
1224  }
1225  }
1226  lasth1 = h1;
1227  lasth2 = h2;
1228 
1229  r1[x0] = GetWaveYPos(-rms[x0] * env[x0], zoomMin, zoomMax,
1230  rect.height, dB, true, dBRange, true);
1231  r2[x0] = GetWaveYPos(rms[x0] * env[x0], zoomMin, zoomMax,
1232  rect.height, dB, true, dBRange, true);
1233  // Make sure the rms isn't larger than the waveform min/max
1234  if (r1[x0] > h1 - 1) {
1235  r1[x0] = h1 - 1;
1236  }
1237  if (r2[x0] < h2 + 1) {
1238  r2[x0] = h2 + 1;
1239  }
1240  if (r2[x0] > r1[x0]) {
1241  r2[x0] = r1[x0];
1242  }
1243 
1244  if (bl[x0] <= -1) {
1245  if (drawStripes) {
1246  // TODO:unify with buffer drawing.
1247  dc.SetPen((bl[x0] % 2) ? muteSamplePen : samplePen);
1248  for (int yy = 0; yy < rect.height / 25 + 1; ++yy) {
1249  // we are drawing over the buffer, but I think DrawLine takes care of this.
1250  AColor::Line(dc,
1251  xx,
1252  rect.y + 25 * yy + (x0 /*+pixAnimOffset*/) % 25,
1253  xx,
1254  rect.y + 25 * yy + (x0 /*+pixAnimOffset*/) % 25 + 6); //take the min so we don't draw past the edge
1255  }
1256  }
1257 
1258  // 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.
1259  // 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.
1260  if (drawWaveform) {
1261  int triX;
1262  dc.SetPen(samplePen);
1263  triX = fabs((double)((x0 + pixAnimOffset) % (2 * rect.height)) - rect.height) + rect.height;
1264  for (int yy = 0; yy < rect.height; ++yy) {
1265  if ((yy + triX) % rect.height == 0) {
1266  dc.DrawPoint(xx, rect.y + yy);
1267  }
1268  }
1269  }
1270 
1271  // Restore the pen for remaining pixel columns!
1272  dc.SetPen(muted ? muteSamplePen : samplePen);
1273  }
1274  else {
1275  AColor::Line(dc, xx, rect.y + h2, xx, rect.y + h1);
1276  }
1277  }
1278 
1279  // Stroke rms over the min-max
1280  dc.SetPen(muted ? muteRmsPen : rmsPen);
1281  for (int x0 = 0; x0 < rect.width; ++x0) {
1282  int xx = rect.x + x0;
1283  if (bl[x0] <= -1) {
1284  }
1285  else if (r1[x0] != r2[x0]) {
1286  AColor::Line(dc, xx, rect.y + r2[x0], xx, rect.y + r1[x0]);
1287  }
1288  }
1289 
1290  // Draw the clipping lines
1291  if (clipcnt) {
1292  dc.SetPen(muted ? muteClippedPen : clippedPen);
1293  while (--clipcnt >= 0) {
1294  int xx = clipped[clipcnt];
1295  AColor::Line(dc, xx, rect.y, xx, rect.y + rect.height);
1296  }
1297  }
1298 }
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:499
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:212
void TrackArtist::DrawNegativeOffsetTrackArrows ( wxDC &  dc,
const wxRect &  rect 
)
private

Definition at line 1009 of file TrackArtist.cpp.

References AColor::Line().

Referenced by DrawClipWaveform().

1010 {
1011  // Draws two black arrows on the left side of the track to
1012  // indicate the user that the track has been time-shifted
1013  // to the left beyond t=0.0.
1014 
1015  dc.SetPen(*wxBLACK_PEN);
1016  AColor::Line(dc,
1017  rect.x + 2, rect.y + 6,
1018  rect.x + 8, rect.y + 6);
1019  AColor::Line(dc,
1020  rect.x + 2, rect.y + 6,
1021  rect.x + 6, rect.y + 2);
1022  AColor::Line(dc,
1023  rect.x + 2, rect.y + 6,
1024  rect.x + 6, rect.y + 10);
1025  AColor::Line(dc,
1026  rect.x + 2, rect.y + rect.height - 8,
1027  rect.x + 8, rect.y + rect.height - 8);
1028  AColor::Line(dc,
1029  rect.x + 2, rect.y + rect.height - 8,
1030  rect.x + 6, rect.y + rect.height - 4);
1031  AColor::Line(dc,
1032  rect.x + 2, rect.y + rect.height - 8,
1033  rect.x + 6, rect.y + rect.height - 12);
1034 }
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 2070 of file TrackArtist.cpp.

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

Referenced by DrawTrack().

2075 {
2077  selectedRegion, zoomInfo);
2078 
2079  WaveTrackCache cache(Track::Pointer<const WaveTrack>(track));
2080  for (const auto &clip: track->GetClips()) {
2081  DrawClipSpectrum(cache, clip.get(), dc, rect, selectedRegion, zoomInfo);
2082  }
2083 }
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:358
wxBrush blankBrush
Definition: TrackArtist.h:190
void TrackArtist::DrawSyncLockTiles ( wxDC *  dc,
wxRect  rect 
)
static

Definition at line 3296 of file TrackArtist.cpp.

References ThemeBase::Image(), and theTheme.

Referenced by DrawBackgroundWithSelection(), and DrawWaveformBackground().

3297 {
3298  wxBitmap syncLockBitmap(theTheme.Image(bmpSyncLockSelTile));
3299 
3300  // Grid spacing is a bit smaller than actual image size
3301  int gridW = syncLockBitmap.GetWidth() - 6;
3302  int gridH = syncLockBitmap.GetHeight() - 8;
3303 
3304  // Horizontal position within the grid, modulo its period
3305  int blockX = (rect.x / gridW) % 5;
3306 
3307  // Amount to offset drawing of first column
3308  int xOffset = rect.x % gridW;
3309  if (xOffset < 0) xOffset += gridW;
3310 
3311  // Check if we're missing an extra column to the left (this can happen
3312  // because the tiles are bigger than the grid spacing)
3313  bool extraCol = false;
3314  if (syncLockBitmap.GetWidth() - gridW > xOffset) {
3315  extraCol = true;
3316  xOffset += gridW;
3317  blockX = (blockX - 1) % 5;
3318  }
3319  // Make sure blockX is non-negative
3320  if (blockX < 0) blockX += 5;
3321 
3322  int xx = 0;
3323  while (xx < rect.width) {
3324  int width = syncLockBitmap.GetWidth() - xOffset;
3325  if (xx + width > rect.width)
3326  width = rect.width - xx;
3327 
3328  //
3329  // Draw each row in this column
3330  //
3331 
3332  // Vertical position in the grid, modulo its period
3333  int blockY = (rect.y / gridH) % 5;
3334 
3335  // Amount to offset drawing of first row
3336  int yOffset = rect.y % gridH;
3337  if (yOffset < 0) yOffset += gridH;
3338 
3339  // Check if we're missing an extra row on top (this can happen because
3340  // the tiles are bigger than the grid spacing)
3341  bool extraRow = false;
3342  if (syncLockBitmap.GetHeight() - gridH > yOffset) {
3343  extraRow = true;
3344  yOffset += gridH;
3345  blockY = (blockY - 1) % 5;
3346  }
3347  // Make sure blockY is non-negative
3348  if (blockY < 0) blockY += 5;
3349 
3350  int yy = 0;
3351  while (yy < rect.height)
3352  {
3353  int height = syncLockBitmap.GetHeight() - yOffset;
3354  if (yy + height > rect.height)
3355  height = rect.height - yy;
3356 
3357  // AWD: draw blocks according to our pattern
3358  if ((blockX == 0 && blockY == 0) || (blockX == 2 && blockY == 1) ||
3359  (blockX == 4 && blockY == 2) || (blockX == 1 && blockY == 3) ||
3360  (blockX == 3 && blockY == 4))
3361  {
3362 
3363  // Do we need to get a sub-bitmap?
3364  if (width != syncLockBitmap.GetWidth() || height != syncLockBitmap.GetHeight()) {
3365  wxBitmap subSyncLockBitmap =
3366  syncLockBitmap.GetSubBitmap(wxRect(xOffset, yOffset, width, height));
3367  dc->DrawBitmap(subSyncLockBitmap, rect.x + xx, rect.y + yy, true);
3368  }
3369  else {
3370  dc->DrawBitmap(syncLockBitmap, rect.x + xx, rect.y + yy, true);
3371  }
3372  }
3373 
3374  // Updates for next row
3375  if (extraRow) {
3376  // Second offset row, still at y = 0; no more extra rows
3377  yOffset -= gridH;
3378  extraRow = false;
3379  }
3380  else {
3381  // Move on in y, no more offset rows
3382  yy += gridH - yOffset;
3383  yOffset = 0;
3384  }
3385  blockY = (blockY + 1) % 5;
3386  }
3387 
3388  // Updates for next column
3389  if (extraCol) {
3390  // Second offset column, still at x = 0; no more extra columns
3391  xOffset -= gridW;
3392  extraCol = false;
3393  }
3394  else {
3395  // Move on in x, no more offset rows
3396  xx += gridW - xOffset;
3397  xOffset = 0;
3398  }
3399  blockX = (blockX + 1) % 5;
3400  }
3401 }
AUDACITY_DLL_API Theme theTheme
Definition: Theme.cpp:215
wxImage & Image(int iIndex)
Definition: Theme.cpp:1240
void TrackArtist::DrawTimeSlider ( wxDC &  dc,
const wxRect &  rect,
bool  rightwards,
bool  highlight 
)
private

Definition at line 2014 of file TrackArtist.cpp.

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

Referenced by DrawWaveform().

2017 {
2018  const int border = 3; // 3 pixels all round.
2019  const int width = 6; // width of the drag box.
2020  const int taper = 6; // how much the box tapers by.
2021  const int barSpacing = 4; // how far apart the bars are.
2022  const int barWidth = 3;
2023  const int xFlat = 3;
2024 
2025  //Enough space to draw in?
2026  if (rect.height <= ((taper+border + barSpacing) * 2)) {
2027  return;
2028  }
2029  if (rect.width <= (width * 2 + border * 3)) {
2030  return;
2031  }
2032 
2033  // The draggable box is tapered towards the direction you drag it.
2034  int leftTaper = rightwards ? 0 : 6;
2035  int rightTaper = rightwards ? 6 : 0;
2036 
2037  int xLeft = rightwards ? (rect.x + border - 2)
2038  : (rect.x + rect.width + 1 - (border + width));
2039  int yTop = rect.y + border;
2040  int yBot = rect.y + rect.height - border - 1;
2041 
2042  AColor::Light(&dc, false, highlight);
2043  AColor::Line(dc, xLeft, yBot - leftTaper, xLeft, yTop + leftTaper);
2044  AColor::Line(dc, xLeft, yTop + leftTaper, xLeft + xFlat, yTop);
2045  AColor::Line(dc, xLeft + xFlat, yTop, xLeft + width, yTop + rightTaper);
2046 
2047  AColor::Dark(&dc, false, highlight);
2048  AColor::Line(dc, xLeft + width, yTop + rightTaper, xLeft + width, yBot - rightTaper);
2049  AColor::Line(dc, xLeft + width, yBot - rightTaper, xLeft + width-xFlat, yBot);
2050  AColor::Line(dc, xLeft + width - xFlat, yBot, xLeft, yBot - leftTaper);
2051 
2052  int firstBar = yTop + taper + taper / 2;
2053  int nBars = (yBot - yTop - taper * 3) / barSpacing + 1;
2054  xLeft += (width - barWidth + 1) / 2;
2055  int yy;
2056  int i;
2057 
2058  AColor::Light(&dc, false, highlight);
2059  for (i = 0;i < nBars; i++) {
2060  yy = firstBar + barSpacing * i;
2061  AColor::Line(dc, xLeft, yy, xLeft + barWidth, yy);
2062  }
2063  AColor::Dark(&dc, false, highlight);
2064  for(i = 0;i < nBars; i++){
2065  yy = firstBar + barSpacing * i + 1;
2066  AColor::Line(dc, xLeft, yy, xLeft + barWidth, yy);
2067  }
2068 }
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 3256 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().

3260 {
3261  track->Draw(context, rect, zoomInfo);
3262  wxRect envRect = rect;
3263  envRect.height -= 2;
3264  double lower = track->GetRangeLower(), upper = track->GetRangeUpper();
3265  if(track->GetDisplayLog()) {
3266  // MB: silly way to undo the work of GetWaveYPos while still getting a logarithmic scale
3267  lower = LINEAR_TO_DB(std::max(1.0e-7, lower)) / mdBrange + 1.0;
3268  upper = LINEAR_TO_DB(std::max(1.0e-7, upper)) / mdBrange + 1.0;
3269  }
3270  track->GetEnvelope()->DrawPoints
3271  (context, envRect, zoomInfo,
3272  track->GetDisplayLog(), mdBrange, lower, upper, false);
3273 }
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:210
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 438 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, Track::Wave, and WaveTrack::Waveform.

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

447 {
448  auto &dc = context.dc;
449  switch (t->GetKind()) {
450  case Track::Wave:
451  {
452  const WaveTrack* wt = static_cast<const WaveTrack*>(t);
453  for (const auto &clip : wt->GetClips()) {
454  clip->ClearDisplayRect();
455  }
456 
457  bool muted = (hasSolo || wt->GetMute()) &&
458  !wt->GetSolo();
459 
460 #if defined(__WXMAC__)
461  wxAntialiasMode aamode = dc.GetGraphicsContext()->GetAntialiasMode();
462  dc.GetGraphicsContext()->SetAntialiasMode(wxANTIALIAS_NONE);
463 #endif
464 
465  switch (wt->GetDisplay()) {
466  case WaveTrack::Waveform:
467  DrawWaveform(context, wt, rect, selectedRegion, zoomInfo,
468  drawEnvelope, bigPoints, drawSliders, muted);
469  break;
470  case WaveTrack::Spectrum:
471  DrawSpectrum(wt, dc, rect, selectedRegion, zoomInfo);
472  break;
473  default:
474  wxASSERT(false);
475  }
476 
477 #if defined(__WXMAC__)
478  dc.GetGraphicsContext()->SetAntialiasMode(aamode);
479 #endif
480 
482  // Exclude right channel of stereo track
483  !(!wt->GetLinked() && wt->GetLink())) {
484  wxFont labelFont(12, wxSWISS, wxNORMAL, wxNORMAL);
485  dc.SetFont(labelFont);
486  dc.SetTextForeground(theTheme.Colour( clrTrackNameText ));
487  dc.DrawText (wt->GetName(), rect.x+10, rect.y); // move right 10 pixels to avoid overwriting <- symbol
488  }
489  break; // case Wave
490  }
491  #ifdef USE_MIDI
492  case Track::Note:
493  {
494  auto nt = static_cast<const NoteTrack *>(t);
495  bool muted = false;
496 #ifdef EXPERIMENTAL_MIDI_OUT
497  muted = (hasSolo || nt->GetMute()) && !nt->GetSolo();
498 #endif
499  DrawNoteTrack((NoteTrack *)t, dc, rect, selectedRegion, zoomInfo, muted);
500  break;
501  }
502  #endif // USE_MIDI
503  case Track::Label:
504  DrawLabelTrack(context, (LabelTrack *)t, rect, selectedRegion, zoomInfo);
505  break;
506  case Track::Time:
507  DrawTimeTrack(context, (TimeTrack *)t, rect, zoomInfo);
508  break;
509  }
510 }
bool GetSolo() const
Definition: Track.h:321
AUDACITY_DLL_API Theme theTheme
Definition: Theme.cpp:215
void DrawLabelTrack(TrackPanelDrawingContext &context, const LabelTrack *track, const wxRect &rect, const SelectedRegion &selectedRegion, const ZoomInfo &zoomInfo)
bool GetLinked() const
Definition: Track.h:218
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:267
A LabelTrack is a Track that holds labels (LabelStruct).
Definition: LabelTrack.h:114
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:358
void DrawSpectrum(const WaveTrack *track, wxDC &dc, const wxRect &rect, const SelectedRegion &selectedRegion, const ZoomInfo &zoomInfo)
wxString GetName() const
Definition: Track.h:212
void DrawTimeTrack(TrackPanelDrawingContext &context, const TimeTrack *track, const wxRect &rect, const ZoomInfo &zoomInfo)
Track * GetLink() const
Definition: Track.cpp:204
bool GetMute() const
Definition: Track.h:320
wxColour & Colour(int iIndex)
Definition: Theme.cpp:1214
WaveTrackDisplay GetDisplay() const
Definition: WaveTrack.h:582
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 341 of file TrackArtist.cpp.

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

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

Definition at line 513 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.

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

1483 {
1484  auto &dc = context.dc;
1485 
1486  bool highlight = false;
1487  bool gripHit = false;
1488 #ifdef EXPERIMENTAL_TRACK_PANEL_HIGHLIGHTING
1489  auto target = dynamic_cast<TimeShiftHandle*>(context.target.get());
1490  gripHit = target && target->IsGripHit();
1491  highlight = target && target->GetTrack().get() == track;
1492 #endif
1493 
1494  const bool dB = !track->GetWaveformSettings().isLinear();
1495 
1497  selectedRegion, zoomInfo);
1498 
1499  for (const auto &clip: track->GetClips())
1500  DrawClipWaveform(context, track, clip.get(), rect, selectedRegion, zoomInfo,
1501  drawEnvelope, bigPoints,
1502  dB, muted);
1503 
1504  // Update cache for locations, e.g. cutlines and merge points
1505  track->UpdateLocationsCache();
1506 
1507 #ifdef EXPERIMENTAL_TRACK_PANEL_HIGHLIGHTING
1508  auto target2 = dynamic_cast<CutlineHandle*>(context.target.get());
1509 #endif
1510  for (const auto loc : track->GetCachedLocations()) {
1511  bool highlight = false;
1512 #ifdef EXPERIMENTAL_TRACK_PANEL_HIGHLIGHTING
1513  highlight =
1514  target2 && target2->GetTrack().get() == track &&
1515  target2->GetLocation() == loc;
1516 #endif
1517  const int xx = zoomInfo.TimeToPosition(loc.pos);
1518  if (xx >= 0 && xx < rect.width) {
1519  dc.SetPen( highlight ? AColor::uglyPen : *wxGREY_PEN );
1520  AColor::Line(dc, (int) (rect.x + xx - 1), rect.y, (int) (rect.x + xx - 1), rect.y + rect.height);
1521  if (loc.typ == WaveTrackLocation::locationCutLine) {
1522  dc.SetPen( highlight ? AColor::uglyPen : *wxRED_PEN );
1523  }
1524  else {
1525 #ifdef EXPERIMENTAL_DA
1526  // JKC Black does not show up enough.
1527  dc.SetPen(highlight ? AColor::uglyPen : *wxWHITE_PEN);
1528 #else
1529  dc.SetPen(highlight ? AColor::uglyPen : *wxBLACK_PEN);
1530 #endif
1531  }
1532  AColor::Line(dc, (int) (rect.x + xx), rect.y, (int) (rect.x + xx), rect.y + rect.height);
1533  dc.SetPen( highlight ? AColor::uglyPen : *wxGREY_PEN );
1534  AColor::Line(dc, (int) (rect.x + xx + 1), rect.y, (int) (rect.x + xx + 1), rect.y + rect.height);
1535  }
1536  }
1537 
1538  if (drawSliders) {
1539  DrawTimeSlider(dc, rect, true, highlight && gripHit); // directed right
1540  DrawTimeSlider(dc, rect, false, highlight && gripHit); // directed left
1541  }
1542 }
const std::vector< Location > & GetCachedLocations() const
Definition: WaveTrack.h:496
bool isLinear() const
void DrawTimeSlider(wxDC &dc, const wxRect &rect, bool rightwards, bool highlight)
const WaveformSettings & GetWaveformSettings() const
Definition: WaveTrack.cpp:715
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:2381
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:358
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 1036 of file TrackArtist.cpp.

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

Referenced by DrawClipWaveform().

1045 {
1046 
1047  // Visually (one vertical slice of the waveform background, on its side;
1048  // the "*" is the actual waveform background we're drawing
1049  //
1050  //1.0 0.0 -1.0
1051  // |--------------------------------|--------------------------------|
1052  // *************** ***************
1053  // | | | |
1054  // maxtop maxbot mintop minbot
1055 
1056  int h = rect.height;
1057  int halfHeight = wxMax(h / 2, 1);
1058  int maxtop, lmaxtop = 0;
1059  int mintop, lmintop = 0;
1060  int maxbot, lmaxbot = 0;
1061  int minbot, lminbot = 0;
1062  bool sel, lsel = false;
1063  int xx, lx = 0;
1064  int l, w;
1065 
1066  dc.SetPen(*wxTRANSPARENT_PEN);
1067  dc.SetBrush(blankBrush);
1068  dc.DrawRectangle(rect);
1069 
1070  double time = zoomInfo.PositionToTime(0, -leftOffset), nextTime;
1071  for (xx = 0; xx < rect.width; ++xx, time = nextTime) {
1072  nextTime = zoomInfo.PositionToTime(xx + 1, -leftOffset);
1073  // First we compute the truncated shape of the waveform background.
1074  // If drawEnvelope is true, then we compute the lower border of the
1075  // envelope.
1076 
1077  maxtop = GetWaveYPos(env[xx], zoomMin, zoomMax,
1078  h, dB, true, dBRange, true);
1079  maxbot = GetWaveYPos(env[xx], zoomMin, zoomMax,
1080  h, dB, false, dBRange, true);
1081 
1082  mintop = GetWaveYPos(-env[xx], zoomMin, zoomMax,
1083  h, dB, false, dBRange, true);
1084  minbot = GetWaveYPos(-env[xx], zoomMin, zoomMax,
1085  h, dB, true, dBRange, true);
1086 
1087  // Make sure it's odd so that a that max and min mirror each other
1088  mintop +=1;
1089  minbot +=1;
1090 
1091  if (!drawEnvelope || maxbot > mintop) {
1092  maxbot = halfHeight;
1093  mintop = halfHeight;
1094  }
1095 
1096  // We don't draw selection color for sync-lock selected tracks.
1097  sel = (t0 <= time && nextTime < t1) && !bIsSyncLockSelected;
1098 
1099  if (lmaxtop == maxtop &&
1100  lmintop == mintop &&
1101  lmaxbot == maxbot &&
1102  lminbot == minbot &&
1103  lsel == sel) {
1104  continue;
1105  }
1106 
1107  dc.SetBrush(lsel ? selectedBrush : unselectedBrush);
1108 
1109  l = rect.x + lx;
1110  w = xx - lx;
1111  if (lmaxbot < lmintop - 1) {
1112  dc.DrawRectangle(l, rect.y + lmaxtop, w, lmaxbot - lmaxtop);
1113  dc.DrawRectangle(l, rect.y + lmintop, w, lminbot - lmintop);
1114  }
1115  else {
1116  dc.DrawRectangle(l, rect.y + lmaxtop, w, lminbot - lmaxtop);
1117  }
1118 
1119  if (highlightEnvelope && lmaxbot < lmintop - 1) {
1120  dc.SetBrush( AColor::uglyBrush );
1121  dc.DrawRectangle(l, rect.y + lmaxbot, w, lmintop - lmaxbot);
1122  }
1123 
1124  lmaxtop = maxtop;
1125  lmintop = mintop;
1126  lmaxbot = maxbot;
1127  lminbot = minbot;
1128  lsel = sel;
1129  lx = xx;
1130  }
1131 
1132  dc.SetBrush(lsel ? selectedBrush : unselectedBrush);
1133  l = rect.x + lx;
1134  w = xx - lx;
1135  if (lmaxbot < lmintop - 1) {
1136  dc.DrawRectangle(l, rect.y + lmaxtop, w, lmaxbot - lmaxtop);
1137  dc.DrawRectangle(l, rect.y + lmintop, w, lminbot - lmintop);
1138  }
1139  else {
1140  dc.DrawRectangle(l, rect.y + lmaxtop, w, lminbot - lmaxtop);
1141  }
1142  if (highlightEnvelope && lmaxbot < lmintop - 1) {
1143  dc.SetBrush( AColor::uglyBrush );
1144  dc.DrawRectangle(l, rect.y + lmaxbot, w, lmintop - lmaxbot);
1145  }
1146 
1147  // If sync-lock selected, draw in linked graphics.
1148  if (bIsSyncLockSelected && t0 < t1) {
1149  const int begin = std::max(0, std::min(rect.width, (int)(zoomInfo.TimeToPosition(t0, -leftOffset))));
1150  const int end = std::max(0, std::min(rect.width, (int)(zoomInfo.TimeToPosition(t1, -leftOffset))));
1151  DrawSyncLockTiles(&dc, wxRect(rect.x + begin, rect.y, end - 1 - begin, rect.height));
1152  }
1153 
1154  //OK, the display bounds are between min and max, which
1155  //is spread across rect.height. Draw the line at the proper place.
1156  if (zeroLevelYCoordinate >= rect.GetTop() &&
1157  zeroLevelYCoordinate <= rect.GetBottom()) {
1158  dc.SetPen(*wxBLACK_PEN);
1159  AColor::Line(dc, rect.x, zeroLevelYCoordinate,
1160  rect.x + rect.width, zeroLevelYCoordinate);
1161  }
1162 }
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 286 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().

287 {
288  theTheme.SetBrushColour( blankBrush, clrBlank );
289  theTheme.SetBrushColour( unselectedBrush, clrUnselected);
290  theTheme.SetBrushColour( selectedBrush, clrSelected);
291  theTheme.SetBrushColour( sampleBrush, clrSample);
292  theTheme.SetBrushColour( selsampleBrush, clrSelSample);
293  theTheme.SetBrushColour( dragsampleBrush, clrDragSample);
294  theTheme.SetBrushColour( blankSelectedBrush, clrBlankSelected);
295 
296  theTheme.SetPenColour( blankPen, clrBlank);
297  theTheme.SetPenColour( unselectedPen, clrUnselected);
298  theTheme.SetPenColour( selectedPen, clrSelected);
299  theTheme.SetPenColour( muteSamplePen, clrMuteSample);
300  theTheme.SetPenColour( odProgressDonePen, clrProgressDone);
301  theTheme.SetPenColour( odProgressNotYetPen, clrProgressNotYet);
302  theTheme.SetPenColour( shadowPen, clrShadow);
303  theTheme.SetPenColour( clippedPen, clrClipped);
304  theTheme.SetPenColour( muteClippedPen, clrMuteClipped);
305  theTheme.SetPenColour( blankSelectedPen,clrBlankSelected);
306 
307  theTheme.SetPenColour( selsamplePen, clrSelSample);
308  theTheme.SetPenColour( muteRmsPen, clrMuteRms);
309 
310  switch( iColorIndex %4 )
311  {
312  default:
313  case 0:
314  theTheme.SetPenColour( samplePen, clrSample);
315  theTheme.SetPenColour( rmsPen, clrRms);
316  break;
317  case 1: // RED
318  samplePen.SetColour( wxColor( 160,10,10 ) );
319  rmsPen.SetColour( wxColor( 230,80,80 ) );
320  break;
321  case 2: // GREEN
322  samplePen.SetColour( wxColor( 35,110,35 ) );
323  rmsPen.SetColour( wxColor( 75,200,75 ) );
324  break;
325  case 3: //BLACK
326  samplePen.SetColour( wxColor( 0,0,0 ) );
327  rmsPen.SetColour( wxColor( 100,100,100 ) );
328  break;
329 
330  }
331 }
wxPen muteClippedPen
Definition: TrackArtist.h:210
AUDACITY_DLL_API Theme theTheme
Definition: Theme.cpp:215
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:1221
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:1227
void TrackArtist::SetMargins ( int  left,
int  top,
int  right,
int  bottom 
)

Definition at line 333 of file TrackArtist.cpp.

References mMarginBottom, mMarginLeft, mMarginRight, and mMarginTop.

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

Definition at line 3275 of file TrackArtist.cpp.

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

Referenced by TrackArtist().

3276 {
3277  mdBrange = gPrefs->Read(ENV_DB_KEY, mdBrange);
3278  mShowClipping = gPrefs->Read(wxT("/GUI/ShowClipping"), mShowClipping);
3279  gPrefs->Read(wxT("/GUI/SampleView"), &mSampleDisplay, 1);
3280  SetColours(0);
3281 }
long mShowClipping
Definition: TrackArtist.h:181
#define ENV_DB_KEY
Definition: GUISettings.h:15
wxFileConfig * gPrefs
Definition: Prefs.cpp:72
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 679 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, WaveTrack::Waveform, and ZOOMLIMIT.

680 {
681  // Label tracks do not have a vruler
682  if (t->GetKind() == Track::Label) {
683  return;
684  }
685 
686  // Time tracks
687  if (t->GetKind() == Track::Time) {
688  const TimeTrack *tt = (TimeTrack *)t;
689  float min, max;
690  min = tt->GetRangeLower() * 100.0;
691  max = tt->GetRangeUpper() * 100.0;
692 
693  vruler->SetBounds(rect.x, rect.y, rect.x + rect.width, rect.y + rect.height-1);
694  vruler->SetOrientation(wxVERTICAL);
695  vruler->SetRange(max, min);
697  vruler->SetUnits(wxT(""));
698  vruler->SetLabelEdges(false);
699  vruler->SetLog(tt->GetDisplayLog());
700  }
701 
702  // All waves have a ruler in the info panel
703  // The ruler needs a bevelled surround.
704  if (t->GetKind() == Track::Wave) {
705  const WaveTrack *wt = static_cast<const WaveTrack*>(t);
706  const float dBRange =
708 
709  const int display = wt->GetDisplay();
710 
711  if (display == WaveTrack::Waveform) {
712  WaveformSettings::ScaleType scaleType =
714 
715  if (scaleType == WaveformSettings::stLinear) {
716  // Waveform
717 
718  float min, max;
719  wt->GetDisplayBounds(&min, &max);
720  if (wt->GetLastScaleType() != scaleType &&
721  wt->GetLastScaleType() != -1)
722  {
723  // do a translation into the linear space
724  wt->SetLastScaleType();
725  wt->SetLastdBRange();
726  float sign = (min >= 0 ? 1 : -1);
727  if (min != 0.) {
728  min = DB_TO_LINEAR(fabs(min) * dBRange - dBRange);
729  if (min < 0.0)
730  min = 0.0;
731  min *= sign;
732  }
733  sign = (max >= 0 ? 1 : -1);
734 
735  if (max != 0.) {
736  max = DB_TO_LINEAR(fabs(max) * dBRange - dBRange);
737  if (max < 0.0)
738  max = 0.0;
739  max *= sign;
740  }
741  wt->SetDisplayBounds(min, max);
742  }
743 
744  vruler->SetBounds(rect.x, rect.y, rect.x + rect.width, rect.y + rect.height - 1);
745  vruler->SetOrientation(wxVERTICAL);
746  vruler->SetRange(max, min);
747  vruler->SetFormat(Ruler::RealFormat);
748  vruler->SetUnits(wxT(""));
749  vruler->SetLabelEdges(false);
750  vruler->SetLog(false);
751  }
752  else {
753  wxASSERT(scaleType == WaveformSettings::stLogarithmic);
755 
756  vruler->SetUnits(wxT(""));
757 
758  float min, max;
759  wt->GetDisplayBounds(&min, &max);
760  float lastdBRange;
761 
762  if (wt->GetLastScaleType() != scaleType &&
763  wt->GetLastScaleType() != -1)
764  {
765  // do a translation into the dB space
766  wt->SetLastScaleType();
767  wt->SetLastdBRange();
768  float sign = (min >= 0 ? 1 : -1);
769  if (min != 0.) {
770  min = (LINEAR_TO_DB(fabs(min)) + dBRange) / dBRange;
771  if (min < 0.0)
772  min = 0.0;
773  min *= sign;
774  }
775  sign = (max >= 0 ? 1 : -1);
776 
777  if (max != 0.) {
778  max = (LINEAR_TO_DB(fabs(max)) + dBRange) / dBRange;
779  if (max < 0.0)
780  max = 0.0;
781  max *= sign;
782  }
783  wt->SetDisplayBounds(min, max);
784  }
785  else if (dBRange != (lastdBRange = wt->GetLastdBRange())) {
786  wt->SetLastdBRange();
787  // Remap the max of the scale
788  const float sign = (max >= 0 ? 1 : -1);
789  float newMax = max;
790  if (max != 0.) {
791 
792 // Ugh, duplicating from TrackPanel.cpp
793 #define ZOOMLIMIT 0.001f
794 
795  const float extreme = LINEAR_TO_DB(2);
796  // recover dB value of max
797  const float dB = std::min(extreme, (float(fabs(max)) * lastdBRange - lastdBRange));
798  // find NEW scale position, but old max may get trimmed if the db limit rises
799  // Don't trim it to zero though, but leave max and limit distinct
800  newMax = sign * std::max(ZOOMLIMIT, (dBRange + dB) / dBRange);
801  // Adjust the min of the scale if we can,
802  // so the db Limit remains where it was on screen, but don't violate extremes
803  if (min != 0.)
804  min = std::max(-extreme, newMax * min / max);
805  }
806 
807  wt->SetDisplayBounds(min, newMax);
808  }
809 
810  if (max > 0) {
811  int top = 0;
812  float topval = 0;
813  int bot = rect.height;
814  float botval = -dBRange;
815 
816  if (min < 0) {
817  bot = top + (int)((max / (max - min))*(bot - top));
818  min = 0;
819  }
820 
821  if (max > 1) {
822  top += (int)((max - 1) / (max - min) * (bot - top));
823  max = 1;
824  }
825 
826  if (max < 1 && max > 0)
827  topval = -((1 - max) * dBRange);
828 
829  if (min > 0) {
830  botval = -((1 - min) * dBRange);
831  }
832 
833  vruler->SetBounds(rect.x, rect.y + top, rect.x + rect.width, rect.y + bot - 1);
834  vruler->SetOrientation(wxVERTICAL);
835  vruler->SetRange(topval, botval);
836  }
837  else
838  vruler->SetBounds(0.0, 0.0, 0.0, 0.0); // A.C.H I couldn't find a way to just disable it?
839  vruler->SetFormat(Ruler::RealLogFormat);
840  vruler->SetLabelEdges(true);
841  vruler->SetLog(false);
842  }
843  }
844  else {
845  wxASSERT(display == WaveTrack::Spectrum);
846  const SpectrogramSettings &settings = wt->GetSpectrogramSettings();
847  float minFreq, maxFreq;
848  wt->GetSpectrumBounds(&minFreq, &maxFreq);
849 
850  switch (settings.scaleType) {
851  default:
852  wxASSERT(false);
854  {
855  // Spectrum
856 
857  if (rect.height < 60)
858  return;
859 
860  /*
861  draw the ruler
862  we will use Hz if maxFreq is < 2000, otherwise we represent kHz,
863  and append to the numbers a "k"
864  */
865  vruler->SetBounds(rect.x, rect.y, rect.x + rect.width, rect.y + rect.height - 1);
866  vruler->SetOrientation(wxVERTICAL);
867  vruler->SetFormat(Ruler::RealFormat);
868  vruler->SetLabelEdges(true);
869  // use kHz in scale, if appropriate
870  if (maxFreq >= 2000) {
871  vruler->SetRange((maxFreq / 1000.), (minFreq / 1000.));
872  vruler->SetUnits(wxT("k"));
873  }
874  else {
875  // use Hz
876  vruler->SetRange((int)(maxFreq), (int)(minFreq));
877  vruler->SetUnits(wxT(""));
878  }
879  vruler->SetLog(false);
880  }
881  break;
887  {
888  // SpectrumLog
889 
890  if (rect.height < 10)
891  return;
892 
893  /*
894  draw the ruler
895  we will use Hz if maxFreq is < 2000, otherwise we represent kHz,
896  and append to the numbers a "k"
897  */
898  vruler->SetBounds(rect.x, rect.y, rect.x + rect.width, rect.y + rect.height - 1);
899  vruler->SetOrientation(wxVERTICAL);
900  vruler->SetFormat(Ruler::IntFormat);
901  vruler->SetLabelEdges(true);
902  vruler->SetRange(maxFreq, minFreq);
903  vruler->SetUnits(wxT(""));
904  vruler->SetLog(true);
905  NumberScale scale(
906  wt->GetSpectrogramSettings().GetScale( minFreq, maxFreq )
907  .Reversal() );
908  vruler->SetNumberScale(&scale);
909  }
910  break;
911  }
912  }
913  }
914 
915 #ifdef USE_MIDI
916  // The note track isn't drawing a ruler at all!
917  // But it needs to!
918  else if (t->GetKind() == Track::Note) {
919  vruler->SetBounds(rect.x, rect.y, rect.x + 1, rect.y + rect.height-1);
920  vruler->SetOrientation(wxVERTICAL);
921  }
922 #endif // USE_MIDI
923 
924  vruler->GetMaxSize(&t->vrulerSize.x, &t->vrulerSize.y);
925 }
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:715
void GetSpectrumBounds(float *min, float *max) const
Definition: WaveTrack.cpp:336
double GetRangeLower() const
Definition: TimeTrack.h:127
void SetDisplayBounds(float min, float max) const
Definition: WaveTrack.cpp:330
int GetLastdBRange() const
Definition: WaveTrack.h:579
NumberScale Reversal() const
Definition: NumberScale.h:83
const SpectrogramSettings & GetSpectrogramSettings() const
Definition: WaveTrack.cpp:684
virtual int GetKind() const
Definition: Track.h:267
NumberScale GetScale(float minFreq, float maxFreq) const
void GetDisplayBounds(float *min, float *max) const
Definition: WaveTrack.cpp:324
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:576
#define LINEAR_TO_DB(x)
Definition: Audacity.h:210
#define ZOOMLIMIT
void SetLastScaleType() const
Definition: WaveTrack.cpp:314
WaveTrackDisplay GetDisplay() const
Definition: WaveTrack.h:582
const double MIN_Threshold_Linear DB_TO_LINEAR(MIN_Threshold_dB)
wxSize vrulerSize
Definition: Track.h:133
void SetLastdBRange() const
Definition: WaveTrack.cpp:319

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: