OpenMP TrackArtist::DrawSpectrum (#165)

- make 2nd loop parallelizable
- remove number scale from both loops, only calculate one time
- initialize Acolor::GetColorGradient separately
This commit is contained in:
Darrell Walisser 2016-09-20 07:15:18 -04:00 committed by Paul Licameli
parent b17a14ccc2
commit 8e1b084f01
2 changed files with 71 additions and 33 deletions

View File

@ -148,10 +148,9 @@ class AColor {
inline void GetColorGradient(float value, inline void GetColorGradient(float value,
AColor::ColorGradientChoice selected, AColor::ColorGradientChoice selected,
bool grayscale, bool grayscale,
unsigned char *red, unsigned char * __restrict red,
unsigned char *green, unsigned char *blue) { unsigned char * __restrict green,
if (!AColor::gradient_inited) unsigned char * __restrict blue) {
AColor::PreComputeGradient();
int idx = value * (AColor::gradientSteps - 1); int idx = value * (AColor::gradientSteps - 1);

View File

@ -151,6 +151,10 @@ audio tracks.
#include <float.h> #include <float.h>
#include <limits> #include <limits>
#ifdef HAVE_ALLOCA_H
#include <alloca.h>
#endif
#include <wx/brush.h> #include <wx/brush.h>
#include <wx/colour.h> #include <wx/colour.h>
#include <wx/dc.h> #include <wx/dc.h>
@ -182,7 +186,6 @@ audio tracks.
#include "widgets/Ruler.h" #include "widgets/Ruler.h"
#include "Theme.h" #include "Theme.h"
#include "AllThemeResources.h" #include "AllThemeResources.h"
#include "Experimental.h" #include "Experimental.h"
#undef PROFILE_WAVEFORM #undef PROFILE_WAVEFORM
@ -2002,7 +2005,6 @@ void TrackArtist::DrawTimeSlider(wxDC & dc,
} }
} }
void TrackArtist::DrawSpectrum(const WaveTrack *track, void TrackArtist::DrawSpectrum(const WaveTrack *track,
wxDC & dc, wxDC & dc,
const wxRect & rect, const wxRect & rect,
@ -2126,8 +2128,8 @@ void TrackArtist::DrawClipSpectrum(WaveTrackCache &waveTrackCache,
const double &t0 = params.t0; const double &t0 = params.t0;
const double &tOffset = params.tOffset; const double &tOffset = params.tOffset;
const auto ssel0 = params.ssel0; const auto &ssel0 = params.ssel0;
const auto ssel1 = params.ssel1; const auto &ssel1 = params.ssel1;
const double &averagePixelsPerSample = params.averagePixelsPerSample; const double &averagePixelsPerSample = params.averagePixelsPerSample;
const double &rate = params.rate; const double &rate = params.rate;
const double &hiddenLeftOffset = params.hiddenLeftOffset; const double &hiddenLeftOffset = params.hiddenLeftOffset;
@ -2148,6 +2150,7 @@ void TrackArtist::DrawClipSpectrum(WaveTrackCache &waveTrackCache,
const bool &isGrayscale = settings.isGrayscale; const bool &isGrayscale = settings.isGrayscale;
const int &range = settings.range; const int &range = settings.range;
const int &gain = settings.gain; const int &gain = settings.gain;
#ifdef EXPERIMENTAL_FIND_NOTES #ifdef EXPERIMENTAL_FIND_NOTES
const bool &fftFindNotes = settings.fftFindNotes; const bool &fftFindNotes = settings.fftFindNotes;
const bool &findNotesMinA = settings.findNotesMinA; const bool &findNotesMinA = settings.findNotesMinA;
@ -2186,7 +2189,22 @@ void TrackArtist::DrawClipSpectrum(WaveTrackCache &waveTrackCache,
const SpectrogramSettings::ScaleType scaleType = settings.scaleType; const SpectrogramSettings::ScaleType scaleType = settings.scaleType;
const NumberScale numberScale(settings.GetScale(minFreq, maxFreq, rate, true)); // nearest frequency to each pixel row from number scale, for selecting
// the desired fft bin(s) for display on that row
float *bins = (float*)alloca(sizeof(*bins)*(hiddenMid.height + 1));
{
const NumberScale numberScale(settings.GetScale(minFreq, maxFreq, rate, true));
NumberScale::Iterator it = numberScale.begin(mid.height);
float nextBin = std::max(0.0f, std::min(float(half - 1), *it));
int yy;
for (yy = 0; yy < hiddenMid.height; ++yy) {
bins[yy] = nextBin;
nextBin = std::max(0.0f, std::min(float(half - 1), *++it));
}
bins[yy] = nextBin;
}
#ifdef EXPERIMENTAL_FFT_Y_GRID #ifdef EXPERIMENTAL_FFT_Y_GRID
const float const float
@ -2266,12 +2284,13 @@ void TrackArtist::DrawClipSpectrum(WaveTrackCache &waveTrackCache,
int *indexes = new int[maxTableSize]; int *indexes = new int[maxTableSize];
#endif //EXPERIMENTAL_FIND_NOTES #endif //EXPERIMENTAL_FIND_NOTES
#ifdef _OPENMP
#pragma omp parallel for
#endif
for (int xx = 0; xx < hiddenMid.width; ++xx) { for (int xx = 0; xx < hiddenMid.width; ++xx) {
NumberScale::Iterator it = numberScale.begin(mid.height);
float nextBin = std::max(0.0f, std::min(float(half - 1), *it));
for (int yy = 0; yy < hiddenMid.height; ++yy) { for (int yy = 0; yy < hiddenMid.height; ++yy) {
const float bin = nextBin; const float bin = bins[yy];
nextBin = std::max(0.0f, std::min(float(half - 1), *++it)); const float nextBin = bins[yy+1];
if (settings.scaleType != SpectrogramSettings::stLogarithmic) { if (settings.scaleType != SpectrogramSettings::stLogarithmic) {
const float value = findValue const float value = findValue
@ -2391,10 +2410,6 @@ void TrackArtist::DrawClipSpectrum(WaveTrackCache &waveTrackCache,
float selBinCenter = float selBinCenter =
((freqLo < 0 || freqHi < 0) ? -1 : sqrt(freqLo * freqHi)) / binUnit; ((freqLo < 0 || freqHi < 0) ? -1 : sqrt(freqLo * freqHi)) / binUnit;
sampleCount w1(0.5 + rate *
(zoomInfo.PositionToTime(0, -leftOffset) - tOffset)
);
const bool isSpectral = settings.SpectralSelectionEnabled(); const bool isSpectral = settings.SpectralSelectionEnabled();
const bool hidden = (ZoomInfo::HIDDEN == zoomInfo.GetFisheyeState()); const bool hidden = (ZoomInfo::HIDDEN == zoomInfo.GetFisheyeState());
const int begin = hidden const int begin = hidden
@ -2423,38 +2438,62 @@ void TrackArtist::DrawClipSpectrum(WaveTrackCache &waveTrackCache,
); );
} }
int correctedX = leftOffset - hiddenLeftOffset; // build color gradient tables (not thread safe)
int fisheyeColumn = 0; if (!AColor::gradient_inited)
for (int xx = 0; xx < mid.width; ++xx, ++correctedX) AColor::PreComputeGradient();
{
const bool inFisheye = zoomInfo.InFisheye(xx, -leftOffset);
float *const uncached =
inFisheye ? &specCache.freq[(fisheyeColumn++) * half] : 0;
auto w0 = w1; // left pixel column of the fisheye
w1 = sampleCount(0.5 + rate * int fisheyeLeft = zoomInfo.GetFisheyeLeftBoundary(-leftOffset);
(zoomInfo.PositionToTime(xx + 1, -leftOffset) - tOffset)
); #ifdef _OPENMP
#pragma omp parallel for
#endif
for (int xx = 0; xx < mid.width; ++xx) {
int correctedX = xx + leftOffset - hiddenLeftOffset;
// in fisheye mode the time scale has changed, so the row values aren't cached
// in the loop above, and must be fetched from fft cache
float* uncached;
if (!zoomInfo.InFisheye(xx, -leftOffset)) {
uncached = 0;
}
else {
int specIndex = (xx - fisheyeLeft) * half;
wxASSERT(specIndex >= 0 && specIndex < specCache.freq.size());
uncached = &specCache.freq[specIndex];
}
// zoomInfo must be queried for each column since with fisheye enabled
// time between columns is variable
auto w0 = sampleCount(0.5 + rate *
(zoomInfo.PositionToTime(xx, -leftOffset) - tOffset));
auto w1 = sampleCount(0.5 + rate *
(zoomInfo.PositionToTime(xx+1, -leftOffset) - tOffset));
bool maybeSelected = ssel0 <= w0 && w1 < ssel1;
NumberScale::Iterator it = numberScale.begin(mid.height);
float nextBin = std::max(0.0f, std::min(float(half - 1), *it));
for (int yy = 0; yy < hiddenMid.height; ++yy) { for (int yy = 0; yy < hiddenMid.height; ++yy) {
const float bin = nextBin; const float bin = bins[yy];
nextBin = std::max(0.0f, std::min(float(half - 1), *++it)); const float nextBin = bins[yy+1];
// For spectral selection, determine what colour // For spectral selection, determine what colour
// set to use. We use a darker selection if // set to use. We use a darker selection if
// in both spectral range and time range. // in both spectral range and time range.
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 we are in the time selected range, then we may use a different color set.
if (ssel0 <= w0 && w1 < ssel1) if (maybeSelected)
selected = selected =
ChooseColorSet(bin, nextBin, selBinLo, selBinCenter, selBinHi, ChooseColorSet(bin, nextBin, selBinLo, selBinCenter, selBinHi,
(xx + leftOffset - hiddenLeftOffset) / DASH_LENGTH, isSpectral); (xx + leftOffset - hiddenLeftOffset) / DASH_LENGTH, isSpectral);
const float value = uncached const float value = uncached
? findValue(uncached, bin, nextBin, half, autocorrelation, gain, range) ? findValue(uncached, bin, nextBin, half, autocorrelation, gain, range)
: clip->mSpecPxCache->values[correctedX * hiddenMid.height + yy]; : clip->mSpecPxCache->values[correctedX * hiddenMid.height + yy];
unsigned char rv, gv, bv; unsigned char rv, gv, bv;
GetColorGradient(value, selected, isGrayscale, &rv, &gv, &bv); GetColorGradient(value, selected, isGrayscale, &rv, &gv, &bv);