1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-09-18 09:00:52 +02:00

rest of fisheye drawing code...

And finally, make ZoomInfo::zoom protected!
This commit is contained in:
Paul Licameli 2015-06-09 16:48:42 -04:00
parent 57e0ce56ed
commit c02652b3ab
2 changed files with 322 additions and 121 deletions

View File

@ -1475,13 +1475,15 @@ struct ClipParameters
(bool spectrum, const WaveTrack *track, const WaveClip *clip, const wxRect &rect,
const SelectedRegion &selectedRegion, const ZoomInfo &zoomInfo)
{
selectedRegion;
tOffset = clip->GetOffset();
rate = clip->GetRate();
h = zoomInfo.h; //The horizontal position in seconds
pps = zoomInfo.zoom; //points-per-second--the zoom level
h = zoomInfo.PositionToTime(0, 0
, true
);
h1 = zoomInfo.PositionToTime(rect.width, 0
, true
);
double sel0 = selectedRegion.t0(); //left selection bound
double sel1 = selectedRegion.t1(); //right selection bound
@ -1494,18 +1496,17 @@ struct ClipParameters
const double trackLen = clip->GetEndTime() - clip->GetStartTime();
tstep = 1.0 / pps; // Seconds per point
tpre = h - tOffset; // offset corrected time of
// left edge of display
tpost = tpre + (rect.width * tstep); // offset corrected time of
tpost = h1 - tOffset; // offset corrected time of
// right edge of display
const double sps = 1. / rate; //seconds-per-sample
// Determine whether we should show individual samples
// or draw circular points as well
showIndividualSamples = (pps / rate > 0.5); //zoomed in a lot
showPoints = (pps / rate > 3.0); //zoomed in even more
averagePixelsPerSample = rect.width / (rate * (h1 - h));
showIndividualSamples = averagePixelsPerSample > 0.5;
// Calculate actual selection bounds so that t0 > 0 and t1 < the
// end of the track
@ -1514,7 +1515,7 @@ struct ClipParameters
if (showIndividualSamples) {
// adjustment so that the last circular point doesn't appear
// to be hanging off the end
t1 += 2. / pps;
t1 += 2. / (averagePixelsPerSample * rate);
}
// Make sure t1 (the right bound) is greater than 0
@ -1542,50 +1543,76 @@ struct ClipParameters
ssel1 = (sampleCount)(0.5 + trackLen * rate);
}
// The variable "mid" will be the rectangle containing the
// The variable "hiddenMid" will be the rectangle containing the
// actual waveform, as opposed to any blank area before
// or after the track.
mid = rect;
// or after the track, as it would appear without the fisheye.
hiddenMid = rect;
// If the left edge of the track is to the right of the left
// edge of the display, then there's some blank area to the
// left of the track. Reduce the "mid"
// rect by size of the blank area.
// left of the track. Reduce the "hiddenMid"
hiddenLeftOffset = 0;
if (tpre < 0) {
// Fill in the area to the left of the track
double delta = rect.width;
if (t0 < tpost) {
delta = (int)((t0 - tpre) * pps);
}
// Offset the rectangle containing the waveform by the width
// of the area we just erased.
mid.x += (int)delta;
mid.width -= (int)delta;
hiddenLeftOffset = std::min(rect.width, int(
zoomInfo.TimeToPosition(tOffset, 0
, true
)
));
hiddenMid.x += hiddenLeftOffset;
hiddenMid.width -= hiddenLeftOffset;
}
// If the right edge of the track is to the left of the the right
// edge of the display, then there's some blank area to the right
// of the track. Reduce the "mid" rect by the
// of the track. Reduce the "hiddenMid" rect by the
// size of the blank area.
if (tpost > t1) {
wxRect post = rect;
if (t1 > tpre) {
post.x += (int)((t1 - tpre) * pps);
const int hiddenRightOffset = std::min(rect.width, int(
zoomInfo.TimeToPosition(tOffset + t1, 0
, true
)
));
hiddenMid.width = std::max(0, hiddenRightOffset - hiddenLeftOffset);
}
post.width = rect.width - (post.x - rect.x);
// Reduce the rectangle containing the waveform by the width
// of the area we just erased.
mid.width -= post.width;
// The variable "mid" will be the rectangle containing the
// actual waveform, as distorted by the fisheye,
// as opposed to any blank area before or after the track.
mid = rect;
// If the left edge of the track is to the right of the left
// edge of the display, then there's some blank area to the
// left of the track. Reduce the "hiddenMid"
leftOffset = 0;
if (tpre < 0) {
leftOffset = std::min(rect.width, int(
zoomInfo.TimeToPosition(tOffset, 0
, false
)
));
mid.x += leftOffset;
mid.width -= leftOffset;
}
// If the right edge of the track is to the left of the the right
// edge of the display, then there's some blank area to the right
// of the track. Reduce the "hiddenMid" rect by the
// size of the blank area.
if (tpost > t1) {
const int distortedRightOffset = std::min(rect.width, int(
zoomInfo.TimeToPosition(tOffset + t1, 0
, false
)
));
mid.width = std::max(0, distortedRightOffset - leftOffset);
}
}
double tOffset;
double rate;
double h; // absolute time of left edge of display
double tstep;
double tpre; // offset corrected time of left edge of display
// double h1;
double h1;
double tpost; // offset corrected time of right edge of display
// Calculate actual selection bounds so that t0 > 0 and t1 < the
@ -1593,16 +1620,61 @@ struct ClipParameters
double t0;
double t1;
double pps;
bool showIndividualSamples, showPoints;
double averagePixelsPerSample;
bool showIndividualSamples;
sampleCount ssel0;
sampleCount ssel1;
wxRect hiddenMid;
int hiddenLeftOffset;
wxRect mid;
int leftOffset;
};
}
namespace {
struct WavePortion {
wxRect rect;
const double averageZoom;
const bool inFisheye;
WavePortion(int x, int y, int w, int h, double zoom, bool i)
: rect(x, y, w, h), averageZoom(zoom), inFisheye(i)
{}
};
void FindWavePortions
(std::vector<WavePortion> &portions, const wxRect &rect, const ZoomInfo &zoomInfo,
const ClipParameters &params)
{
// If there is no fisheye, then only one rectangle has nonzero width.
// If there is a fisheye, make rectangles for before and after
// (except when they are squeezed to zero width), and at least one for inside
// the fisheye.
ZoomInfo::Intervals intervals;
zoomInfo.FindIntervals(params.rate, intervals, rect.x);
ZoomInfo::Intervals::const_iterator it = intervals.begin(), end = intervals.end(), prev;
wxASSERT(it != end && it->position == rect.x);
const int rightmost = rect.x + rect.width;
for (int left = rect.x; left < rightmost;) {
while (it != end && it->position <= left)
prev = it++;
const int right = std::max(left, int(
it != end ? it->position : rightmost
));
const int width = right - left;
if (width > 0)
portions.push_back(
WavePortion(left, rect.y, width, rect.height,
prev->averageZoom, prev->inFisheye)
);
left = right;
}
}
}
void TrackArtist::DrawClipWaveform(WaveTrack *track,
WaveClip *clip,
wxDC & dc,
@ -1619,88 +1691,171 @@ void TrackArtist::DrawClipWaveform(WaveTrack *track,
#endif
const ClipParameters params(false, track, clip, rect, selectedRegion, zoomInfo);
const wxRect &mid = params.mid;
// The "mid" rect contains the part of the display actually
// containing the waveform. If it's empty, we're done.
if (mid.width <= 0) {
const wxRect &hiddenMid = params.hiddenMid;
// The "hiddenMid" rect contains the part of the display actually
// containing the waveform, as it appears without the fisheye. If it's empty, we're done.
if (hiddenMid.width <= 0) {
return;
}
const double &t0 = params.t0;
const double &pps = params.pps;
const double &tOffset = params.tOffset;
const double &tstep = params.tstep;
const bool &showIndividualSamples = params.showIndividualSamples;
const bool &showPoints = params.showPoints;
const double &h = params.h;
const double &tpre = params.tpre;
const double &tpost = params.tpost;
const double &t1 = params.t1;
const double &averagePixelsPerSample = params.averagePixelsPerSample;
const double &rate = params.rate;
double leftOffset = params.leftOffset;
const wxRect &mid = params.mid;
// Calculate sample-based offset-corrected selection
dc.SetPen(*wxTRANSPARENT_PEN);
// If we get to this point, the clip is actually visible on the
// screen, so remember the display rectangle.
clip->SetDisplayRect(mid);
clip->SetDisplayRect(hiddenMid);
// The bounds (controlled by vertical zooming; -1.0...1.0
// by default)
float zoomMin, zoomMax;
track->GetDisplayBounds(&zoomMin, &zoomMax);
// Get the values of the envelope corresponding to each pixel
// in the display, and use these to compute the height of the
// track at each pixel
double *envValues = new double[mid.width];
clip->GetEnvelope()->GetValues(envValues, mid.width, t0 + tOffset, tstep);
std::vector<double> vEnv(mid.width);
double *const env = &vEnv[0];
clip->GetEnvelope()->GetValues(env, mid.width, leftOffset, zoomInfo);
// Draw the background of the track, outlining the shape of
// the envelope and using a colored pen for the selected
// part of the waveform
DrawWaveformBackground(dc, mid.x - rect.x, mid,
envValues,
DrawWaveformBackground(dc, leftOffset, mid,
env,
zoomMin, zoomMax, dB,
selectedRegion, zoomInfo, drawEnvelope,
!track->GetSelected());
if (!showIndividualSamples) {
WaveDisplay display(mid.width);
WaveDisplay display(hiddenMid.width);
bool isLoadingOD = false;//true if loading on demand block in sequence.
const double pps =
averagePixelsPerSample * rate;
if (!params.showIndividualSamples) {
// The WaveClip class handles the details of computing the shape
// of the waveform. The only way GetWaveDisplay will fail is if
// there's a serious error, like some of the waveform data can't
// be loaded. So if the function returns false, we can just exit.
// Note that we compute the full width display even if there is a
// fisheye hiding part of it, because of the caching. If the
// fisheye moves over the background, there is then less to do when
// redrawing.
if (!clip->GetWaveDisplay(display,
t0, pps, isLoadingOD)) {
t0, pps, isLoadingOD))
return;
}
DrawMinMaxRMS(dc, mid, envValues,
// For each portion separately, we will decide to draw
// it as min/max/rms or as individual samples.
std::vector<WavePortion> portions;
FindWavePortions(portions, rect, zoomInfo, params);
const unsigned nPortions = portions.size();
// Require at least 1/2 pixel per sample for drawing individual samples.
const double threshold1 = 0.5 * rate;
// Require at least 3 pixels per sample for drawing the draggable points.
const double threshold2 = 3 * rate;
for (unsigned ii = 0; ii < nPortions; ++ii) {
WavePortion &portion = portions[ii];
const bool showIndividualSamples = portion.averageZoom > threshold1;
const bool showPoints = portion.averageZoom > threshold2;
wxRect& rect = portion.rect;
rect.Intersect(mid);
wxASSERT(rect.width >= 0);
float *useMin = 0, *useMax = 0, *useRms = 0;
int *useBl = 0;
WaveDisplay fisheyeDisplay(rect.width);
int skipped = 0, skippedLeft = 0, skippedRight = 0;
if (portion.inFisheye) {
if (!showIndividualSamples) {
fisheyeDisplay.Allocate();
const sampleCount numSamples = clip->GetNumSamples();
// Get wave display data for different magnification
int jj = 0;
for (; jj < rect.width; ++jj) {
const double time =
zoomInfo.PositionToTime(jj, -leftOffset) - tOffset;
const sampleCount sample = (sampleCount)floor(time * rate + 0.5);
if (sample < 0) {
++rect.x;
++skippedLeft;
continue;
}
if (sample >= numSamples)
break;
fisheyeDisplay.where[jj - skippedLeft] = sample;
}
skippedRight = rect.width - jj;
skipped = skippedRight + skippedLeft;
rect.width -= skipped;
// where needs a sentinel
if (jj > 0)
fisheyeDisplay.where[jj - skippedLeft] =
1 + fisheyeDisplay.where[jj - skippedLeft - 1];
fisheyeDisplay.width -= skipped;
// Get a wave display for the fisheye, uncached.
if (rect.width > 0)
if (!clip->GetWaveDisplay(
fisheyeDisplay, t0, -1.0, // ignored
isLoadingOD))
continue; // serious error. just don't draw??
useMin = fisheyeDisplay.min;
useMax = fisheyeDisplay.max;
useRms = fisheyeDisplay.rms;
useBl = fisheyeDisplay.bl;
}
}
else {
const int pos = leftOffset - params.hiddenLeftOffset;
useMin = display.min + pos;
useMax = display.max + pos;
useRms = display.rms + pos;
useBl = display.bl + pos;
}
leftOffset += skippedLeft;
if (rect.width > 0) {
if (!showIndividualSamples) {
std::vector<double> vEnv2(rect.width);
double *const env2 = &vEnv2[0];
clip->GetEnvelope()->GetValues(env2, rect.width, leftOffset, zoomInfo);
DrawMinMaxRMS(dc, rect, env2,
zoomMin, zoomMax, dB,
display.min, display.max, display.rms, display.bl,
useMin, useMax, useRms, useBl,
isLoadingOD, muted
#ifdef EXPERIMENTAL_OUTPUT_DISPLAY
, track->GetChannelGain(track->GetChannel())
#endif
);
}
else {
DrawIndividualSamples(dc, mid.x - rect.x, mid,
zoomMin, zoomMax, dB,
clip, zoomInfo, bigPoints, showPoints, muted);
else
DrawIndividualSamples(dc, leftOffset, rect, zoomMin, zoomMax, dB,
clip, zoomInfo,
bigPoints, showPoints, muted);
}
leftOffset += rect.width + skippedRight;
}
if (drawEnvelope) {
DrawEnvelope(dc, mid, envValues, zoomMin, zoomMax, dB);
DrawEnvelope(dc, mid, env, zoomMin, zoomMax, dB);
clip->GetEnvelope()->DrawPoints(dc, rect, zoomInfo, dB, zoomMin, zoomMax);
}
delete[] envValues;
// Draw arrows on the left side if the track extends to the left of the
// beginning of time. :)
if (h == 0.0 && tOffset < 0.0) {
@ -1880,19 +2035,26 @@ void TrackArtist::DrawClipSpectrum(WaveTrackCache &waveTrackCache,
enum { DASH_LENGTH = 10 /* pixels */ };
const ClipParameters params(true, track, clip, rect, selectedRegion, zoomInfo);
const wxRect &mid = params.mid;
// The "mid" rect contains the part of the display actually
// containing the waveform. If it's empty, we're done.
if (mid.width <= 0) {
const wxRect &hiddenMid = params.hiddenMid;
// The "hiddenMid" rect contains the part of the display actually
// containing the waveform, as it appears without the fisheye. If it's empty, we're done.
if (hiddenMid.width <= 0) {
return;
}
const double &t0 = params.t0;
const double &pps = params.pps;
const double &tstep = params.tstep;
const double &tOffset = params.tOffset;
const double &ssel0 = params.ssel0;
const double &ssel1 = params.ssel1;
const double &averagePixelsPerSample = params.averagePixelsPerSample;
const double &rate = params.rate;
const double &hiddenLeftOffset = params.hiddenLeftOffset;
const double &leftOffset = params.leftOffset;
const wxRect &mid = params.mid;
// If we get to this point, the clip is actually visible on the
// screen, so remember the display rectangle.
clip->SetDisplayRect(hiddenMid);
double freqLo = SelectedRegion::UndefinedFrequency;
double freqHi = SelectedRegion::UndefinedFrequency;
@ -1923,19 +2085,23 @@ void TrackArtist::DrawClipSpectrum(WaveTrackCache &waveTrackCache,
// and then paint this directly to our offscreen
// bitmap. Note that this could be optimized even
// more, but for now this is not bad. -dmazzoni
wxImage *image = new wxImage((int) mid.width, (int) mid.height);
if (!image)return;
wxImage *image = new wxImage((int)mid.width, (int)mid.height);
if (!image)
return;
unsigned char *data = image->GetData();
const int half = GetSpectrumWindowSize(!autocorrelation) / 2;
const double binUnit = rate / (2 * half);
const float *freq = 0;
const sampleCount *where = 0;
bool updated = clip->GetSpectrogram(waveTrackCache, freq, where, mid.width,
bool updated;
{
const double pps = averagePixelsPerSample * rate;
updated = clip->GetSpectrogram(waveTrackCache, freq, where, hiddenMid.width,
t0, pps, autocorrelation);
}
int ifreq = lrint(rate/2);
int ifreq = lrint(rate / 2);
int maxFreq;
if (!logF)
@ -1990,7 +2156,8 @@ void TrackArtist::DrawClipSpectrum(WaveTrackCache &waveTrackCache,
}
#endif //EXPERIMENTAL_FFT_Y_GRID
if (!updated && clip->mSpecPxCache->valid && (clip->mSpecPxCache->len == mid.height * mid.width)
if (!updated && clip->mSpecPxCache->valid &&
(clip->mSpecPxCache->len == hiddenMid.height * hiddenMid.width)
&& gain == clip->mSpecPxCache->gain
&& range == clip->mSpecPxCache->range
&& minFreq == clip->mSpecPxCache->minFreq
@ -2011,7 +2178,7 @@ void TrackArtist::DrawClipSpectrum(WaveTrackCache &waveTrackCache,
else {
// Update the spectrum pixel cache
delete clip->mSpecPxCache;
clip->mSpecPxCache = new SpecPxCache(mid.width * mid.height);
clip->mSpecPxCache = new SpecPxCache(hiddenMid.width * hiddenMid.height);
clip->mSpecPxCache->valid = true;
clip->mSpecPxCache->gain = gain;
clip->mSpecPxCache->range = range;
@ -2044,15 +2211,15 @@ void TrackArtist::DrawClipSpectrum(WaveTrackCache &waveTrackCache,
int *indexes = new int[maxTableSize];
#endif //EXPERIMENTAL_FIND_NOTES
for (int xx = 0; xx < mid.width; ++xx)
for (int xx = 0; xx < hiddenMid.width; ++xx)
{
if (!logF) {
for (int yy = 0; yy < mid.height; ++yy) {
for (int yy = 0; yy < hiddenMid.height; ++yy) {
float bin0 = float(yy) * binPerPx + minBin;
float bin1 = float(yy + 1) * binPerPx + minBin;
const float value = findValue
(freq + half * xx, bin0, bin1, half, autocorrelation, gain, range);
clip->mSpecPxCache->values[xx * mid.height + yy] = value;
clip->mSpecPxCache->values[xx * hiddenMid.height + yy] = value;
}
}
else {
@ -2099,7 +2266,7 @@ void TrackArtist::DrawClipSpectrum(WaveTrackCache &waveTrackCache,
}
// The f2pix helper macro converts a frequency into a pixel coordinate.
#define f2pix(f) (logf(f)-lmins)/(lmaxs-lmins)*mid.height
#define f2pix(f) (logf(f)-lmins)/(lmaxs-lmins)*hiddenMid.height
// Possibly quantize the maxima frequencies and create the pixel block limits.
for (int i=0; i < maximas; i++) {
@ -2122,8 +2289,8 @@ void TrackArtist::DrawClipSpectrum(WaveTrackCache &waveTrackCache,
double yy2_base = exp(lmin) / binUnit;
float yy2 = yy2_base;
double exp_scale_per_height = exp(scale / mid.height);
for (int yy = 0; yy < mid.height; ++yy) {
double exp_scale_per_height = exp(scale / hiddenMid.height);
for (int yy = 0; yy < hiddenMid.height; ++yy) {
if (int(yy2) >= half)
yy2=half-1;
if (yy2<0)
@ -2167,13 +2334,12 @@ void TrackArtist::DrawClipSpectrum(WaveTrackCache &waveTrackCache,
value = findValue
(freq + half * xx, bin0, bin1, half, autocorrelation, gain, range);
}
clip->mSpecPxCache->values[xx * mid.height + yy] = value;
clip->mSpecPxCache->values[xx * hiddenMid.height + yy] = value;
yy2 = yy2_base;
} // each yy
} // is logF
} // each xx
} // updating cache
float selBinLo = freqLo / binUnit;
@ -2181,24 +2347,56 @@ void TrackArtist::DrawClipSpectrum(WaveTrackCache &waveTrackCache,
float selBinCenter =
((freqLo < 0 || freqHi < 0) ? -1 : sqrt(freqLo * freqHi)) / binUnit;
sampleCount w1 = sampleCount(0.5 + rate *
t0
sampleCount w1(0.5 + rate *
(zoomInfo.PositionToTime(0, -leftOffset) - tOffset)
);
for (int xx = 0; xx < mid.width; ++xx)
const bool hidden = (ZoomInfo::HIDDEN == zoomInfo.GetFisheyeState());
const int begin = hidden
? 0
: std::max(0, int(zoomInfo.GetFisheyeLeftBoundary(-leftOffset)));
const int end = hidden
? 0
: std::min(mid.width, int(zoomInfo.GetFisheyeRightBoundary(-leftOffset)));
const int numPixels = std::max(0, end - begin);
const int zeroPaddingFactor = autocorrelation ? 1 : settings.zeroPaddingFactor;
SpecCache specCache
(numPixels, autocorrelation, -1,
t0, settings.windowType,
settings.windowSize, zeroPaddingFactor, settings.frequencyGain);
if (numPixels > 0) {
for (int ii = begin; ii < end; ++ii) {
const double time = zoomInfo.PositionToTime(ii, -leftOffset) - tOffset;
specCache.where[ii - begin] = sampleCount(0.5 + rate * time);
}
specCache.Populate
(settings, waveTrackCache,
0, 0, numPixels,
clip->GetNumSamples(),
tOffset, rate,
autocorrelation);
}
int correctedX = leftOffset - hiddenLeftOffset;
int fisheyeColumn = 0;
for (int xx = 0; xx < mid.width; ++xx, ++correctedX)
{
const bool inFisheye = zoomInfo.InFisheye(xx, -leftOffset);
float *const uncached =
inFisheye ? &specCache.freq[(fisheyeColumn++) * half] : 0;
sampleCount w0 = w1;
w1 = sampleCount(0.5 + rate *
(t0 + (xx+1) * tstep)
(zoomInfo.PositionToTime(xx + 1, -leftOffset) - tOffset)
);
// TODO: The logF and non-logF case are very similar.
// They should be merged and simplified.
if (!logF)
{
for (int yy = 0; yy < mid.height; ++yy) {
float bin0 = float (yy) * binPerPx + minBin;
float bin1 = float (yy + 1) * binPerPx + minBin;
for (int yy = 0; yy < hiddenMid.height; ++yy) {
float bin0 = float(yy) * binPerPx + minBin;
float bin1 = float(yy + 1) * binPerPx + minBin;
// For spectral selection, determine what colour
// set to use. We use a darker selection if
@ -2211,12 +2409,14 @@ void TrackArtist::DrawClipSpectrum(WaveTrackCache &waveTrackCache,
{
bool isSpectral = ((track->GetDisplay() == WaveTrack::SpectralSelectionDisplay) ||
(track->GetDisplay() == WaveTrack::SpectralSelectionLogDisplay));
selected = ChooseColorSet( bin0, bin1, selBinLo, selBinCenter, selBinHi, xx/DASH_LENGTH, isSpectral );
selected = ChooseColorSet(bin0, bin1, selBinLo, selBinCenter, selBinHi,
(xx + leftOffset - hiddenLeftOffset) / DASH_LENGTH, isSpectral);
}
unsigned char rv, gv, bv;
const float value =
clip->mSpecPxCache->values[xx * mid.height + yy];
const float value = uncached
? findValue(uncached, bin0, bin1, half, autocorrelation, gain, range)
: clip->mSpecPxCache->values[correctedX * hiddenMid.height + yy];
GetColorGradient(value, selected, isGrayscale, &rv, &gv, &bv);
int px = ((mid.height - 1 - yy) * mid.width + xx) * 3;
data[px++] = rv;
@ -2228,8 +2428,8 @@ void TrackArtist::DrawClipSpectrum(WaveTrackCache &waveTrackCache,
{
double yy2_base=exp(lmin)/binUnit;
float yy2 = yy2_base;
double exp_scale_per_height = exp(scale/mid.height);
for (int yy = 0; yy < mid.height; ++yy) {
double exp_scale_per_height = exp(scale / hiddenMid.height);
for (int yy = 0; yy < hiddenMid.height; ++yy) {
if (int(yy2)>=half)
yy2=half-1;
if (yy2<0)
@ -2243,20 +2443,21 @@ void TrackArtist::DrawClipSpectrum(WaveTrackCache &waveTrackCache,
yy3=0;
float bin1 = float(yy3);
AColor::ColorGradientChoice selected =
AColor::ColorGradientUnselected;
AColor::ColorGradientChoice selected = AColor::ColorGradientUnselected;
// If we are in the time selected range, then we may use a different color set.
if (ssel0 <= w0 && w1 < ssel1)
{
bool isSpectral = ((track->GetDisplay() == WaveTrack::SpectralSelectionDisplay) ||
(track->GetDisplay() == WaveTrack::SpectralSelectionLogDisplay));
selected = ChooseColorSet( bin0, bin1, selBinLo, selBinCenter, selBinHi, xx/DASH_LENGTH, isSpectral );
selected = ChooseColorSet(
bin0, bin1, selBinLo, selBinCenter, selBinHi,
(xx + leftOffset - hiddenLeftOffset) / DASH_LENGTH, isSpectral);
}
const float value = clip->mSpecPxCache->values[xx * mid.height + yy];
yy2 = yy2_base;
unsigned char rv, gv, bv;
const float value = uncached
? findValue(uncached, bin0, bin1, half, autocorrelation, gain, range)
: clip->mSpecPxCache->values[correctedX * hiddenMid.height + yy];
GetColorGradient(value, selected, isGrayscale, &rv, &gv, &bv);
#ifdef EXPERIMENTAL_FFT_Y_GRID
@ -2271,13 +2472,11 @@ void TrackArtist::DrawClipSpectrum(WaveTrackCache &waveTrackCache,
data[px++] = rv;
data[px++] = gv;
data[px] = bv;
} // each yy
} // logF
} // each xx
// If we get to this point, the clip is actually visible on the
// screen, so remember the display rectangle.
clip->SetDisplayRect(mid);
yy2 = yy2_base;
}
}
}
wxBitmap converted = wxBitmap(*image);

View File

@ -32,6 +32,8 @@ public:
double h; // h pos in secs
double screen; // screen width in secs
protected:
double zoom; // pixels per second
public: