Spectrum analyzer update (#5160)

* advanced config: expose hidden constants to user screen
* advanced config: add support for FFT window overlapping
* waterfall: display at native resolution on high-DPI screens
* waterfall: add cursor and improve label density
* FFT: fix normalization so that 0 dBFS matches full-scale sinewave
* FFT: decouple data acquisition from processing and display
* FFT: separate lock for reallocation (to avoid some needless waiting)
* moved ranges and other constants to a separate file
* debug: better performance measurements
* minor fixes
* build the ringbuffer library as part of LMMS core
This commit is contained in:
Martin Pavelek
2019-11-21 14:44:18 +01:00
committed by Johannes Lorenz
parent 2f0010270e
commit da73ddd242
26 changed files with 1867 additions and 364 deletions

View File

@@ -50,7 +50,17 @@ SaControls::SaControls(Analyzer *effect) :
m_freqRangeModel(this, tr("Frequency range")),
m_ampRangeModel(this, tr("Amplitude range")),
m_blockSizeModel(this, tr("FFT block size")),
m_windowModel(this, tr("FFT window type"))
m_windowModel(this, tr("FFT window type")),
// Advanced settings knobs
m_envelopeResolutionModel(0.25f, 0.1f, 3.0f, 0.05f, this, tr("Peak envelope resolution")),
m_spectrumResolutionModel(1.5f, 0.1f, 3.0f, 0.05f, this, tr("Spectrum display resolution")),
m_peakDecayFactorModel(0.992f, 0.95f, 0.999f, 0.001f, this, tr("Peak decay multiplier")),
m_averagingWeightModel(0.15f, 0.01f, 0.5f, 0.01f, this, tr("Averaging weight")),
m_waterfallHeightModel(300.0f, 50.0f, 1000.0f, 50.0f, this, tr("Waterfall history size")),
m_waterfallGammaModel(0.30f, 0.10f, 1.00f, 0.05f, this, tr("Waterfall gamma correction")),
m_windowOverlapModel(2.0f, 1.0f, 4.0f, 1.0f, this, tr("FFT window overlap")),
m_zeroPaddingModel(2.0f, 0.0f, 4.0f, 1.0f, this, tr("FFT zero padding"))
{
// Frequency and amplitude ranges; order must match
// FREQUENCY_RANGES and AMPLITUDE_RANGES defined in SaControls.h
@@ -62,10 +72,10 @@ SaControls::SaControls(Analyzer *effect) :
m_freqRangeModel.setValue(m_freqRangeModel.findText(tr("Full (auto)")));
m_ampRangeModel.addItem(tr("Extended"));
m_ampRangeModel.addItem(tr("Default"));
m_ampRangeModel.addItem(tr("Audible"));
m_ampRangeModel.addItem(tr("Noise"));
m_ampRangeModel.setValue(m_ampRangeModel.findText(tr("Default")));
m_ampRangeModel.addItem(tr("Loud"));
m_ampRangeModel.addItem(tr("Silent"));
m_ampRangeModel.setValue(m_ampRangeModel.findText(tr("Audible")));
// FFT block size labels are generated automatically, based on
// FFT_BLOCK_SIZES vector defined in fft_helpers.h
@@ -95,12 +105,15 @@ SaControls::SaControls(Analyzer *effect) :
// Colors
// Background color is defined by Qt / theme.
// Make sure the sum of colors for L and R channel stays lower or equal
// to 255. Otherwise the Waterfall pixels may overflow back to 0 even when
// the input signal isn't clipping (over 1.0).
// Make sure the sum of colors for L and R channel results into a neutral
// color that has at least one component equal to 255 (i.e. ideally white).
// This means the color overflows to zero exactly when signal reaches
// clipping threshold, indicating the problematic frequency to user.
// Mono waterfall color should have similarly at least one component at 255.
m_colorL = QColor(51, 148, 204, 135);
m_colorR = QColor(204, 107, 51, 135);
m_colorMono = QColor(51, 148, 204, 204);
m_colorMonoW = QColor(64, 185, 255, 255);
m_colorBG = QColor(7, 7, 7, 255); // ~20 % gray (after gamma correction)
m_colorGrid = QColor(30, 34, 38, 255); // ~40 % gray (slightly cold / blue)
m_colorLabels = QColor(192, 202, 212, 255); // ~90 % gray (slightly cold / blue)
@@ -126,6 +139,15 @@ void SaControls::loadSettings(const QDomElement &_this)
m_ampRangeModel.loadSettings(_this, "RangeY");
m_blockSizeModel.loadSettings(_this, "BlockSize");
m_windowModel.loadSettings(_this, "WindowType");
m_envelopeResolutionModel.loadSettings(_this, "EnvelopeRes");
m_spectrumResolutionModel.loadSettings(_this, "SpectrumRes");
m_peakDecayFactorModel.loadSettings(_this, "PeakDecayFactor");
m_averagingWeightModel.loadSettings(_this, "AverageWeight");
m_waterfallHeightModel.loadSettings(_this, "WaterfallHeight");
m_waterfallGammaModel.loadSettings(_this, "WaterfallGamma");
m_windowOverlapModel.loadSettings(_this, "WindowOverlap");
m_zeroPaddingModel.loadSettings(_this, "ZeroPadding");
}
@@ -141,4 +163,14 @@ void SaControls::saveSettings(QDomDocument &doc, QDomElement &parent)
m_ampRangeModel.saveSettings(doc, parent, "RangeY");
m_blockSizeModel.saveSettings(doc, parent, "BlockSize");
m_windowModel.saveSettings(doc, parent, "WindowType");
m_envelopeResolutionModel.saveSettings(doc, parent, "EnvelopeRes");
m_spectrumResolutionModel.saveSettings(doc, parent, "SpectrumRes");
m_peakDecayFactorModel.saveSettings(doc, parent, "PeakDecayFactor");
m_averagingWeightModel.saveSettings(doc, parent, "AverageWeight");
m_waterfallHeightModel.saveSettings(doc, parent, "WaterfallHeight");
m_waterfallGammaModel.saveSettings(doc, parent, "WaterfallGamma");
m_windowOverlapModel.saveSettings(doc, parent, "WindowOverlap");
m_zeroPaddingModel.saveSettings(doc, parent, "ZeroPadding");
}