mirror of
https://github.com/LMMS/lmms.git
synced 2026-05-24 06:37:52 -04:00
Improve spectrum analyzer performance by caching most used computations (#6003)
This commit is contained in:
@@ -225,12 +225,9 @@ void SaProcessor::analyze(LocklessRingBuffer<sampleFrame> &ring_buffer)
|
||||
if (band_end - band_start > 1.0)
|
||||
{
|
||||
// band spans multiple pixels: draw all pixels it covers
|
||||
for (target = (int)band_start; target < (int)band_end; target++)
|
||||
for (target = std::max((int)band_start, 0); target < band_end && target < waterfallWidth(); target++)
|
||||
{
|
||||
if (target >= 0 && target < waterfallWidth())
|
||||
{
|
||||
pixel[target] = makePixel(m_normSpectrumL[i], m_normSpectrumR[i]);
|
||||
}
|
||||
pixel[target] = makePixel(m_normSpectrumL[i], m_normSpectrumR[i]);
|
||||
}
|
||||
// save remaining portion of the band for the following band / pixel
|
||||
// (in case the next band uses sub-pixel drawing)
|
||||
@@ -265,12 +262,9 @@ void SaProcessor::analyze(LocklessRingBuffer<sampleFrame> &ring_buffer)
|
||||
else
|
||||
{
|
||||
// Linear: always draws one or more pixels per band
|
||||
for (target = (int)band_start; target < band_end; target++)
|
||||
for (target = std::max((int)band_start, 0); target < band_end && target < waterfallWidth(); target++)
|
||||
{
|
||||
if (target >= 0 && target < waterfallWidth())
|
||||
{
|
||||
pixel[target] = makePixel(m_normSpectrumL[i], m_normSpectrumR[i]);
|
||||
}
|
||||
pixel[target] = makePixel(m_normSpectrumL[i], m_normSpectrumR[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -573,6 +567,9 @@ float SaProcessor::getFreqRangeMax() const
|
||||
|
||||
|
||||
// Map frequency to pixel x position on a display of given width.
|
||||
// NOTE: Results of this function may be cached by SaSpectrumView. If you use
|
||||
// a new function call or variable that can affect results of this function,
|
||||
// make sure to also add it as a trigger for cache update in SaSpectrumView.
|
||||
float SaProcessor::freqToXPixel(float freq, unsigned int width) const
|
||||
{
|
||||
if (m_controls->m_logXModel.value())
|
||||
|
||||
@@ -47,7 +47,13 @@ SaSpectrumView::SaSpectrumView(SaControls *controls, SaProcessor *processor, QWi
|
||||
m_controls(controls),
|
||||
m_processor(processor),
|
||||
m_freezeRequest(false),
|
||||
m_frozen(false)
|
||||
m_frozen(false),
|
||||
m_cachedRangeMin(-1),
|
||||
m_cachedRangeMax(-1),
|
||||
m_cachedLogX(true),
|
||||
m_cachedDisplayWidth(0),
|
||||
m_cachedBinCount(0),
|
||||
m_cachedSampleRate(0)
|
||||
{
|
||||
setMinimumSize(360, 170);
|
||||
setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
|
||||
@@ -69,6 +75,9 @@ SaSpectrumView::SaSpectrumView(SaControls *controls, SaProcessor *processor, QWi
|
||||
|
||||
m_cursor = QPointF(0, 0);
|
||||
|
||||
// Initialize the size of bin → pixel X position LUT to the maximum allowed number of bins + 1.
|
||||
m_cachedBinToX.resize(FFT_BLOCK_SIZES.back() / 2 + 2);
|
||||
|
||||
#ifdef SA_DEBUG
|
||||
m_execution_avg = m_path_avg = m_draw_avg = 0;
|
||||
#endif
|
||||
@@ -348,10 +357,31 @@ QPainterPath SaSpectrumView::makePath(std::vector<float> &displayBuffer, float r
|
||||
// Bins falling to interval [x_start, x_next) contribute to a single point.
|
||||
float max = m_displayBottom;
|
||||
float x_start = -1; // lower bound of currently constructed point
|
||||
|
||||
// Speed up bin → x position translation by building a LUT cache.
|
||||
// Update the cache only when range or display width are changed.
|
||||
float rangeMin = m_processor->getFreqRangeMin(m_controls->m_logXModel.value());
|
||||
float rangeMax = m_processor->getFreqRangeMax();
|
||||
if (rangeMin != m_cachedRangeMin || rangeMax != m_cachedRangeMax || m_displayWidth != m_cachedDisplayWidth ||
|
||||
m_controls->m_logXModel.value() != m_cachedLogX || m_processor->binCount() + 1 != m_cachedBinCount ||
|
||||
m_processor->getSampleRate() != m_cachedSampleRate)
|
||||
{
|
||||
m_cachedRangeMin = rangeMin;
|
||||
m_cachedRangeMax = rangeMax;
|
||||
m_cachedDisplayWidth = m_displayWidth;
|
||||
m_cachedLogX = m_controls->m_logXModel.value();
|
||||
m_cachedBinCount = m_processor->binCount() + 1;
|
||||
m_cachedSampleRate = m_processor->getSampleRate();
|
||||
for (unsigned int n = 0; n < m_cachedBinCount; n++)
|
||||
{
|
||||
m_cachedBinToX[n] = freqToXPixel(binToFreq(n), m_displayWidth);
|
||||
}
|
||||
}
|
||||
|
||||
for (unsigned int n = 0; n < m_processor->binCount(); n++)
|
||||
{
|
||||
float x = freqToXPixel(binToFreq(n), m_displayWidth);
|
||||
float x_next = freqToXPixel(binToFreq(n + 1), m_displayWidth);
|
||||
float x = m_cachedBinToX[n];
|
||||
float x_next = m_cachedBinToX[n + 1];
|
||||
float y = ampToYPixel(displayBuffer[n], m_displayBottom);
|
||||
|
||||
// consider making a point only if x falls within display bounds
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <QPainterPath>
|
||||
#include <QWidget>
|
||||
|
||||
@@ -120,6 +121,15 @@ private:
|
||||
unsigned int m_displayRight;
|
||||
unsigned int m_displayWidth;
|
||||
|
||||
// cached frequency bin → x position conversion for better performance
|
||||
std::vector<float> m_cachedBinToX;
|
||||
float m_cachedRangeMin;
|
||||
float m_cachedRangeMax;
|
||||
bool m_cachedLogX;
|
||||
unsigned int m_cachedDisplayWidth;
|
||||
unsigned int m_cachedBinCount;
|
||||
unsigned int m_cachedSampleRate;
|
||||
|
||||
#ifdef SA_DEBUG
|
||||
float m_execution_avg;
|
||||
float m_refresh_avg;
|
||||
|
||||
Reference in New Issue
Block a user