diff --git a/src/analyzer/analyzerwaveform.h b/src/analyzer/analyzerwaveform.h index 658ceb98e89..cfe49fb9368 100644 --- a/src/analyzer/analyzerwaveform.h +++ b/src/analyzer/analyzerwaveform.h @@ -26,6 +26,16 @@ inline CSAMPLE scaleSignal(CSAMPLE invalue, FilterIndex index = FilterCount) { } else { return std::pow(invalue, 2.0f * 0.316f); } + + // According to this discussion + // https://github.com/mixxxdj/mixxx/issues/6352 + // it looks like this scaling is done to accentuate + // low level information. + + // This scaling can be undone with a function in + // waveform/renderers/waveformrenderersignalbase.h + // but arguable it would be better not to do this scaling here at all + // and do it (or not) at the waveform renderer side. } struct WaveformStride { diff --git a/src/waveform/renderers/allshader/waveformrendererfiltered.cpp b/src/waveform/renderers/allshader/waveformrendererfiltered.cpp index 27bf733fdec..9b2ef711da3 100644 --- a/src/waveform/renderers/allshader/waveformrendererfiltered.cpp +++ b/src/waveform/renderers/allshader/waveformrendererfiltered.cpp @@ -60,7 +60,7 @@ void WaveformRendererFiltered::paintGL() { // Per-band gain from the EQ knobs. float allGain{1.0}; float bandGain[3] = {1.0, 1.0, 1.0}; - getGains(&allGain, &bandGain[0], &bandGain[1], &bandGain[2]); + getGains(&allGain, true, &bandGain[0], &bandGain[1], &bandGain[2]); const float breadth = static_cast(m_waveformRenderer->getBreadth()) * devicePixelRatio; const float halfBreadth = breadth / 2.0f; diff --git a/src/waveform/renderers/allshader/waveformrendererhsv.cpp b/src/waveform/renderers/allshader/waveformrendererhsv.cpp index eb2a88af894..6fe30596841 100644 --- a/src/waveform/renderers/allshader/waveformrendererhsv.cpp +++ b/src/waveform/renderers/allshader/waveformrendererhsv.cpp @@ -59,7 +59,7 @@ void WaveformRendererHSV::paintGL() { (lastVisualFrame - firstVisualFrame) / static_cast(length); float allGain(1.0); - getGains(&allGain, nullptr, nullptr, nullptr); + getGains(&allGain, false, nullptr, nullptr, nullptr); // Get base color of waveform in the HSV format (s and v isn't use) float h, s, v; @@ -130,6 +130,8 @@ void WaveformRendererHSV::paintGL() { maxMid[chn] = static_cast(u8maxMid); maxHigh[chn] = static_cast(u8maxHigh); maxAll[chn] = static_cast(u8maxAll); + // Uncomment to undo scaling with pow(value, 2.0f * 0.316f) done in analyzerwaveform.h + // maxAll[chn] = unscale(u8maxAll); } float total{}; diff --git a/src/waveform/renderers/allshader/waveformrendererlrrgb.cpp b/src/waveform/renderers/allshader/waveformrendererlrrgb.cpp index be49d260bdd..f687253e196 100644 --- a/src/waveform/renderers/allshader/waveformrendererlrrgb.cpp +++ b/src/waveform/renderers/allshader/waveformrendererlrrgb.cpp @@ -65,7 +65,8 @@ void WaveformRendererLRRGB::paintGL() { // Per-band gain from the EQ knobs. float allGain(1.0), lowGain(1.0), midGain(1.0), highGain(1.0); - getGains(&allGain, &lowGain, &midGain, &highGain); + // applyCompensation = false, as we scale to match filtered.all + getGains(&allGain, false, &lowGain, &midGain, &highGain); const float breadth = static_cast(m_waveformRenderer->getBreadth()) * devicePixelRatio; const float halfBreadth = breadth / 2.0f; @@ -137,6 +138,8 @@ void WaveformRendererLRRGB::paintGL() { float maxMid = static_cast(u8maxMid); float maxHigh = static_cast(u8maxHigh); float maxAll = static_cast(u8maxAll); + // Uncomment to undo scaling with pow(value, 2.0f * 0.316f) done in analyzerwaveform.h + // float maxAll = unscale(u8maxAll); // Calculate the squared magnitude of the maxLow, maxMid and maxHigh values. // We take the square root to get the magnitude below. diff --git a/src/waveform/renderers/allshader/waveformrendererrgb.cpp b/src/waveform/renderers/allshader/waveformrendererrgb.cpp index 076acfb2278..ff1ad60f88f 100644 --- a/src/waveform/renderers/allshader/waveformrendererrgb.cpp +++ b/src/waveform/renderers/allshader/waveformrendererrgb.cpp @@ -65,7 +65,8 @@ void WaveformRendererRGB::paintGL() { // Per-band gain from the EQ knobs. float allGain(1.0), lowGain(1.0), midGain(1.0), highGain(1.0); - getGains(&allGain, &lowGain, &midGain, &highGain); + // applyCompensation = false, as we scale to match filtered.all + getGains(&allGain, false, &lowGain, &midGain, &highGain); const float breadth = static_cast(m_waveformRenderer->getBreadth()) * devicePixelRatio; const float halfBreadth = breadth / 2.0f; @@ -139,6 +140,8 @@ void WaveformRendererRGB::paintGL() { float maxMid = static_cast(u8maxMid); float maxHigh = static_cast(u8maxHigh); float maxAllChn[2]{static_cast(u8maxAllChn[0]), static_cast(u8maxAllChn[1])}; + // Uncomment to undo scaling with pow(value, 2.0f * 0.316f) done in analyzerwaveform.h + // float maxAllChn[2]{unscale(u8maxAllChn[0]), unscale(u8maxAllChn[1])}; // Calculate the squared magnitude of the maxLow, maxMid and maxHigh values. // We take the square root to get the magnitude below. diff --git a/src/waveform/renderers/allshader/waveformrenderersimple.cpp b/src/waveform/renderers/allshader/waveformrenderersimple.cpp index 3537c92d874..772efa193de 100644 --- a/src/waveform/renderers/allshader/waveformrenderersimple.cpp +++ b/src/waveform/renderers/allshader/waveformrenderersimple.cpp @@ -65,7 +65,7 @@ void WaveformRendererSimple::paintGL() { // Per-band gain from the EQ knobs. float allGain{1.0}; float bandGain[3] = {1.0, 1.0, 1.0}; - getGains(&allGain, &bandGain[0], &bandGain[1], &bandGain[2]); + getGains(&allGain, false, &bandGain[0], &bandGain[1], &bandGain[2]); const float breadth = static_cast(m_waveformRenderer->getBreadth()) * devicePixelRatio; const float halfBreadth = breadth / 2.0f; @@ -120,6 +120,9 @@ void WaveformRendererSimple::paintGL() { for (int i = visualIndexStart + chn; i < visualIndexStop + chn; i += 2) { const WaveformData& waveformData = data[i]; const float filteredAll = static_cast(waveformData.filtered.all); + // Uncomment to undo scaling with pow(value, 2.0f * 0.316f) done + // in analyzerwaveform.h const float filteredAll = + // unscale(waveformData.filtered.all); max[chn] = math_max(max[chn], filteredAll); } diff --git a/src/waveform/renderers/glslwaveformrenderersignal.cpp b/src/waveform/renderers/glslwaveformrenderersignal.cpp index 00864ddb9db..0855268ef7e 100644 --- a/src/waveform/renderers/glslwaveformrenderersignal.cpp +++ b/src/waveform/renderers/glslwaveformrenderersignal.cpp @@ -297,7 +297,7 @@ void GLSLWaveformRendererSignal::draw(QPainter* painter, QPaintEvent* /*event*/) // Per-band gain from the EQ knobs. float lowGain(1.0), midGain(1.0), highGain(1.0), allGain(1.0); - getGains(&allGain, &lowGain, &midGain, &highGain); + getGains(&allGain, true, &lowGain, &midGain, &highGain); const auto firstVisualIndex = static_cast( m_waveformRenderer->getFirstDisplayedPosition() * trackSamples / diff --git a/src/waveform/renderers/glwaveformrendererfilteredsignal.cpp b/src/waveform/renderers/glwaveformrendererfilteredsignal.cpp index 1b116205566..56d7060c3a2 100644 --- a/src/waveform/renderers/glwaveformrendererfilteredsignal.cpp +++ b/src/waveform/renderers/glwaveformrendererfilteredsignal.cpp @@ -67,7 +67,7 @@ void GLWaveformRendererFilteredSignal::draw(QPainter* painter, QPaintEvent* /*ev // Per-band gain from the EQ knobs. float allGain(1.0), lowGain(1.0), midGain(1.0), highGain(1.0); - getGains(&allGain, &lowGain, &midGain, &highGain); + getGains(&allGain, true, &lowGain, &midGain, &highGain); if (m_alignment == Qt::AlignCenter) { glMatrixMode(GL_PROJECTION); diff --git a/src/waveform/renderers/glwaveformrendererrgb.cpp b/src/waveform/renderers/glwaveformrendererrgb.cpp index 0df2c6344e8..337468e0383 100644 --- a/src/waveform/renderers/glwaveformrendererrgb.cpp +++ b/src/waveform/renderers/glwaveformrendererrgb.cpp @@ -67,7 +67,7 @@ void GLWaveformRendererRGB::draw(QPainter* painter, QPaintEvent* /*event*/) { // Per-band gain from the EQ knobs. float allGain(1.0), lowGain(1.0), midGain(1.0), highGain(1.0); - getGains(&allGain, &lowGain, &midGain, &highGain); + getGains(&allGain, true, &lowGain, &midGain, &highGain); if (m_alignment == Qt::AlignCenter) { glMatrixMode(GL_PROJECTION); diff --git a/src/waveform/renderers/glwaveformrenderersimplesignal.cpp b/src/waveform/renderers/glwaveformrenderersimplesignal.cpp index c2291445103..d12920d53d1 100644 --- a/src/waveform/renderers/glwaveformrenderersimplesignal.cpp +++ b/src/waveform/renderers/glwaveformrenderersimplesignal.cpp @@ -68,7 +68,7 @@ void GLWaveformRendererSimpleSignal::draw(QPainter* painter, QPaintEvent* /*even glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); float allGain(1.0); - getGains(&allGain, nullptr, nullptr, nullptr); + getGains(&allGain, false, nullptr, nullptr, nullptr); if (m_alignment == Qt::AlignCenter) { glMatrixMode(GL_PROJECTION); diff --git a/src/waveform/renderers/waveformrendererfilteredsignal.cpp b/src/waveform/renderers/waveformrendererfilteredsignal.cpp index ee0cf9bb771..1fcfb069213 100644 --- a/src/waveform/renderers/waveformrendererfilteredsignal.cpp +++ b/src/waveform/renderers/waveformrendererfilteredsignal.cpp @@ -76,7 +76,7 @@ void WaveformRendererFilteredSignal::draw(QPainter* painter, // Per-band gain from the EQ knobs. float allGain(1.0), lowGain(1.0), midGain(1.0), highGain(1.0); - getGains(&allGain, &lowGain, &midGain, &highGain); + getGains(&allGain, true, &lowGain, &midGain, &highGain); const float breadth = m_waveformRenderer->getBreadth(); const float halfBreadth = breadth / 2.0f; diff --git a/src/waveform/renderers/waveformrendererhsv.cpp b/src/waveform/renderers/waveformrendererhsv.cpp index 693942eefdf..6087bfe5d9d 100644 --- a/src/waveform/renderers/waveformrendererhsv.cpp +++ b/src/waveform/renderers/waveformrendererhsv.cpp @@ -73,7 +73,7 @@ void WaveformRendererHSV::draw( (double)m_waveformRenderer->getLength(); float allGain(1.0); - getGains(&allGain, nullptr, nullptr, nullptr); + getGains(&allGain, false, nullptr, nullptr, nullptr); // Get base color of waveform in the HSV format (s and v isn't use) float h, s, v; diff --git a/src/waveform/renderers/waveformrendererrgb.cpp b/src/waveform/renderers/waveformrendererrgb.cpp index 57397da8975..f47def6493f 100644 --- a/src/waveform/renderers/waveformrendererrgb.cpp +++ b/src/waveform/renderers/waveformrendererrgb.cpp @@ -71,7 +71,7 @@ void WaveformRendererRGB::draw( // Per-band gain from the EQ knobs. float allGain(1.0), lowGain(1.0), midGain(1.0), highGain(1.0); - getGains(&allGain, &lowGain, &midGain, &highGain); + getGains(&allGain, true, &lowGain, &midGain, &highGain); QColor color; diff --git a/src/waveform/renderers/waveformrenderersignalbase.cpp b/src/waveform/renderers/waveformrenderersignalbase.cpp index 11a28bec7c1..bf2b2938483 100644 --- a/src/waveform/renderers/waveformrenderersignalbase.cpp +++ b/src/waveform/renderers/waveformrenderersignalbase.cpp @@ -169,11 +169,14 @@ void WaveformRendererSignalBase::setup(const QDomNode& node, onSetup(node); } -void WaveformRendererSignalBase::getGains(float* pAllGain, float* pLowGain, - float* pMidGain, float* pHighGain) { +void WaveformRendererSignalBase::getGains(float* pAllGain, + bool applyCompensation, + float* pLowGain, + float* pMidGain, + float* pHighGain) { WaveformWidgetFactory* factory = WaveformWidgetFactory::instance(); if (pAllGain) { - *pAllGain = static_cast(m_waveformRenderer->getGain()) * + *pAllGain = static_cast(m_waveformRenderer->getGain(applyCompensation)) * static_cast(factory->getVisualGain(WaveformWidgetFactory::All)); ; } @@ -223,3 +226,13 @@ void WaveformRendererSignalBase::getGains(float* pAllGain, float* pLowGain, } } } + +std::span WaveformRendererSignalBase::unscaleTable() { + // Table to undo the scaling std::pow(invalue, 2.0f * 0.316f); + // done in scaleSignal in analyzerwaveform.h + static std::array result; + for (int i = 0; i < 256; i++) { + result[i] = 255.f * std::pow(static_cast(i) / 255.f, 1.f / 0.632f); + } + return result; +} diff --git a/src/waveform/renderers/waveformrenderersignalbase.h b/src/waveform/renderers/waveformrenderersignalbase.h index f22a241867d..83252e592ea 100644 --- a/src/waveform/renderers/waveformrenderersignalbase.h +++ b/src/waveform/renderers/waveformrenderersignalbase.h @@ -1,7 +1,9 @@ #pragma once -#include "waveformrendererabstract.h" +#include + #include "skin/legacy/skincontext.h" +#include "waveformrendererabstract.h" class ControlProxy; class WaveformSignalColors; @@ -20,8 +22,20 @@ class WaveformRendererSignalBase : public WaveformRendererAbstract { protected: void deleteControls(); - void getGains(float* pAllGain, float* pLowGain, float* pMidGain, - float* highGain); + void getGains(float* pAllGain, + bool applyCompensation, + float* pLowGain, + float* pMidGain, + float* highGain); + + static std::span unscaleTable(); + inline float unscale(unsigned char value) { + // The all and hi components of the waveform data are scaled with pow(value, 2.0f * 0.316f) + // (see analyzerwaveform.h). This function can be used to undo that scaling, + // but apparently it is intentional. + static const auto table = unscaleTable(); + return table[value]; + } protected: ControlProxy* m_pEQEnabled; diff --git a/src/waveform/renderers/waveformwidgetrenderer.cpp b/src/waveform/renderers/waveformwidgetrenderer.cpp index 6def0215d5b..d4877c4b727 100644 --- a/src/waveform/renderers/waveformwidgetrenderer.cpp +++ b/src/waveform/renderers/waveformwidgetrenderer.cpp @@ -116,9 +116,7 @@ void WaveformWidgetRenderer::onPreRender(VSyncThread* vsyncThread) { //Fetch parameters before rendering in order the display all sub-renderers with the same values double rateRatio = m_pRateRatioCO->get(); - // This gain adjustment compensates for an arbitrary /2 gain chop in - // EnginePregain. See the comment there. - m_gain = m_pGainControlObject->get() * 2; + m_gain = m_pGainControlObject->get(); // Compute visual sample to pixel ratio // Allow waveform to spread one visual sample across a hundred pixels diff --git a/src/waveform/renderers/waveformwidgetrenderer.h b/src/waveform/renderers/waveformwidgetrenderer.h index 0928ff9b130..511cb6196d8 100644 --- a/src/waveform/renderers/waveformwidgetrenderer.h +++ b/src/waveform/renderers/waveformwidgetrenderer.h @@ -104,8 +104,21 @@ class WaveformWidgetRenderer { double getZoomFactor() const { return m_zoomFactor; } - double getGain() const { - return m_gain; + double getGain(bool applyCompensation) const { + // m_gain was always multiplied by 2.0, according to a comment: + // + // "This gain adjustment compensates for an arbitrary /2 gain chop in + // EnginePregain. See the comment there." + // + // However, no comment there seems to explain this, and it resulted + // in renderers that use the filtered.all data for the amplitude, to + // be twice the expected value. + // But without this compensation, renderers that use the combined + // lo, mid, hi values became much lower than expected. By making this + // optional we move the decision to each renderer whether to apply the + // compensation or not, in order to have a more similar amplitude across + // waveform renderers + return applyCompensation ? m_gain * 2.f : m_gain; } double getTrackSamples() const { return m_trackSamples;