Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

stem waveformrenderer using rendergraph #14192

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
126 changes: 65 additions & 61 deletions src/waveform/renderers/allshader/waveformrendererstem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,79 +5,103 @@
#include <QOpenGLTexture>

#include "engine/engine.h"
#include "rendergraph/material/rgbamaterial.h"
#include "rendergraph/vertexupdaters/rgbavertexupdater.h"
#include "track/track.h"
#include "util/assert.h"
#include "util/math.h"
#include "waveform/renderers/allshader/matrixforwidgetgeometry.h"
#include "waveform/renderers/allshader/rgbdata.h"
#include "waveform/renderers/waveformwidgetrenderer.h"
#include "waveform/waveform.h"

using namespace rendergraph;

namespace {
constexpr int kMaxSupportedStems = 4;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This constant is already duplicated twice in engine/channels/enginedeck.cpp and analyzer/constants.h (my fault). How would you feel about using either of them? analyzer probably makes the most sense here

} // anonymous namespace

namespace allshader {

WaveformRendererStem::WaveformRendererStem(
WaveformWidgetRenderer* waveformWidget,
::WaveformRendererAbstract::PositionSource type)
: WaveformRendererSignalBase(waveformWidget),
m_isSlipRenderer(type == ::WaveformRendererAbstract::Slip) {
initForRectangles<RGBAMaterial>(0);
setUsePreprocess(true);
}

void WaveformRendererStem::onSetup(const QDomNode&) {
}

void WaveformRendererStem::initializeGL() {
m_shader.init();
m_textureShader.init();
auto group = m_pEQEnabled->getKey().group;
for (int stemIdx = 1; stemIdx <= mixxx::kMaxSupportedStems; stemIdx++) {
bool WaveformRendererStem::init() {
auto group = m_waveformRenderer->getGroup();
VERIFY_OR_DEBUG_ASSERT(!group.isEmpty()) {
return false;
}
for (int stemIdx = 1; stemIdx <= kMaxSupportedStems; stemIdx++) {
DEBUG_ASSERT(group.endsWith("]"));
QString stemGroup = QStringLiteral("%1Stem%2]")
.arg(group.left(group.size() - 1),
QString::number(stemIdx));
m_pStemGain.emplace_back(
std::make_unique<ControlProxy>(stemGroup,
std::make_unique<PollingControlProxy>(stemGroup,
QStringLiteral("volume")));
m_pStemMute.emplace_back(std::make_unique<ControlProxy>(
m_pStemMute.emplace_back(std::make_unique<PollingControlProxy>(
stemGroup, QStringLiteral("mute")));
}
return true;
}

void WaveformRendererStem::preprocess() {
if (!preprocessInner()) {
if (geometry().vertexCount() != 0) {
geometry().allocate(0);
markDirtyGeometry();
}
}
}

void WaveformRendererStem::paintGL() {
bool WaveformRendererStem::preprocessInner() {
TrackPointer pTrack = m_waveformRenderer->getTrackInfo();

if (!pTrack || (m_isSlipRenderer && !m_waveformRenderer->isSlipActive())) {
return;
return false;
}

auto stemInfo = pTrack->getStemInfo();
// If this track isn't a stem track, skip the rendering
if (stemInfo.isEmpty()) {
return;
return false;
}
auto positionType = m_isSlipRenderer ? ::WaveformRendererAbstract::Slip
: ::WaveformRendererAbstract::Play;

ConstWaveformPointer waveform = pTrack->getWaveform();
if (waveform.isNull()) {
return;
return false;
}

const int dataSize = waveform->getDataSize();
if (dataSize <= 1) {
return;
return false;
}

const WaveformData* data = waveform->data();
if (data == nullptr) {
return;
return false;
}
// If this waveform doesn't contain stem data, skip the rendering
if (!waveform->hasStem()) {
return;
return false;
}

uint selectedStems = m_waveformRenderer->getSelectedStems();

const float devicePixelRatio = m_waveformRenderer->getDevicePixelRatio();
const int length = static_cast<int>(m_waveformRenderer->getLength() * devicePixelRatio);
const int length = static_cast<int>(m_waveformRenderer->getLength());
const int pixelLength = static_cast<int>(m_waveformRenderer->getLength() * devicePixelRatio);
const float invDevicePixelRatio = 1.f / devicePixelRatio;
const float halfPixelSize = 0.5 / devicePixelRatio;

Check failure on line 104 in src/waveform/renderers/allshader/waveformrendererstem.cpp

View workflow job for this annotation

GitHub Actions / Ubuntu 24.04

conversion from ‘double’ to ‘float’ may change value [-Werror=float-conversion]

Check warning on line 104 in src/waveform/renderers/allshader/waveformrendererstem.cpp

View workflow job for this annotation

GitHub Actions / coverage

conversion from ‘double’ to ‘float’ may change value [-Wfloat-conversion]

// See waveformrenderersimple.cpp for a detailed explanation of the frame and index calculation
const int visualFramesSize = dataSize / 2;
Expand All @@ -88,14 +112,14 @@

// Represents the # of visual frames per horizontal pixel.
const double visualIncrementPerPixel =
(lastVisualFrame - firstVisualFrame) / static_cast<double>(length);
(lastVisualFrame - firstVisualFrame) / static_cast<double>(pixelLength);

// Per-band gain from the EQ knobs.
float allGain(1.0);
// applyCompensation = true, as we scale to match filtered.all
getGains(&allGain, false, nullptr, nullptr, nullptr);

const float breadth = static_cast<float>(m_waveformRenderer->getBreadth()) * devicePixelRatio;
const float breadth = static_cast<float>(m_waveformRenderer->getBreadth());
const float halfBreadth = breadth / 2.0f;

const float heightFactor = allGain * halfBreadth / m_maxValue;
Expand All @@ -106,22 +130,22 @@

const int numVerticesPerLine = 6; // 2 triangles

const int reserved = numVerticesPerLine * (8 * length + 1);
const int reserved = numVerticesPerLine * (8 * pixelLength + 1);

m_vertices.clear();
m_vertices.reserve(reserved);
m_colors.clear();
m_colors.reserve(reserved);
geometry().setDrawingMode(Geometry::DrawingMode::Triangles);
geometry().allocate(reserved);
markDirtyGeometry();

m_vertices.addRectangle(0.f,
halfBreadth - 0.5f * devicePixelRatio,
static_cast<float>(length),
m_isSlipRenderer ? halfBreadth : halfBreadth + 0.5f * devicePixelRatio);
m_colors.addForRectangle(0.f, 0.f, 0.f, 0.f);
RGBAVertexUpdater vertexUpdater{geometry().vertexDataAs<Geometry::RGBAColoredPoint2D>()};
vertexUpdater.addRectangle({0.f,
halfBreadth - 0.5f},
{static_cast<float>(length),
m_isSlipRenderer ? halfBreadth : halfBreadth + 0.5f},
{0.f, 0.f, 0.f, 0.f});

const double maxSamplingRange = visualIncrementPerPixel / 2.0;

for (int visualIdx = 0; visualIdx < length; ++visualIdx) {
for (int visualIdx = 0; visualIdx < pixelLength; ++visualIdx) {
for (int stemIdx = 0; stemIdx < mixxx::kMaxSupportedStems; stemIdx++) {
// Stem is drawn twice with different opacity level, this allow to
// see the maximum signal by transparency
Expand All @@ -138,7 +162,7 @@
const int visualIndexStop =
std::min(std::max(visualFrameStop, visualFrameStart + 1) * 2, dataSize - 1);

const float fVisualIdx = static_cast<float>(visualIdx);
const float fVisualIdx = static_cast<float>(visualIdx) * invDevicePixelRatio;

// Find the max values for current eq in the waveform data.
// - Max of left and right
Expand All @@ -165,43 +189,23 @@
}

// Lines are thin rectangles
// shawdow
m_vertices.addRectangle(fVisualIdx - 0.5f,
halfBreadth - heightFactor * max,
fVisualIdx + 0.5f,
m_isSlipRenderer ? halfBreadth : halfBreadth + heightFactor * max);

m_colors.addForRectangle(color_r, color_g, color_b, color_a);
// shadow
vertexUpdater.addRectangle({fVisualIdx - halfPixelSize,
halfBreadth - heightFactor * max},
{fVisualIdx + halfPixelSize,
m_isSlipRenderer ? halfBreadth : halfBreadth + heightFactor * max},
{color_r, color_g, color_b, color_a});
}
}

xVisualFrame += visualIncrementPerPixel;
}

DEBUG_ASSERT(reserved == m_vertices.size());
DEBUG_ASSERT(reserved == m_colors.size());

const QMatrix4x4 matrix = matrixForWidgetGeometry(m_waveformRenderer, true);

const int matrixLocation = m_shader.matrixLocation();
const int positionLocation = m_shader.positionLocation();
const int colorLocation = m_shader.colorLocation();

m_shader.bind();
m_shader.enableAttributeArray(positionLocation);
m_shader.enableAttributeArray(colorLocation);

m_shader.setUniformValue(matrixLocation, matrix);

m_shader.setAttributeArray(
positionLocation, GL_FLOAT, m_vertices.constData(), 2);
m_shader.setAttributeArray(
colorLocation, GL_FLOAT, m_colors.constData(), 4);
DEBUG_ASSERT(reserved == vertexUpdater.index());

glDrawArrays(GL_TRIANGLES, 0, m_vertices.size());
markDirtyMaterial();

m_shader.disableAttributeArray(positionLocation);
m_shader.disableAttributeArray(colorLocation);
m_shader.release();
return true;
}

} // namespace allshader
32 changes: 15 additions & 17 deletions src/waveform/renderers/allshader/waveformrendererstem.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,9 @@

#include <vector>

#include "rendergraph/openglnode.h"
#include "shaders/rgbashader.h"
#include "shaders/textureshader.h"
#include "control/pollingcontrolproxy.h"
#include "rendergraph/geometrynode.h"
#include "util/class.h"
#include "waveform/renderers/allshader/rgbadata.h"
#include "waveform/renderers/allshader/vertexdata.h"
#include "waveform/renderers/allshader/waveformrenderersignalbase.h"

class QOpenGLTexture;
Expand All @@ -18,30 +15,31 @@ class WaveformRendererStem;

class allshader::WaveformRendererStem final
: public allshader::WaveformRendererSignalBase,
public rendergraph::OpenGLNode {
public rendergraph::GeometryNode {
public:
explicit WaveformRendererStem(WaveformWidgetRenderer* waveformWidget,
::WaveformRendererAbstract::PositionSource type =
::WaveformRendererAbstract::Play);

// override ::WaveformRendererSignalBase
// Pure virtual from WaveformRendererSignalBase, not used
void onSetup(const QDomNode& node) override;

void initializeGL() override;
void paintGL() override;
bool init() override;

private:
mixxx::RGBAShader m_shader;
mixxx::TextureShader m_textureShader;
VertexData m_vertices;
RGBAData m_colors;
bool supportsSlip() const override {
return true;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After testing, looks like the stem waveform doesn't support the slip animation

}

// Virtuals for rendergraph::Node
void preprocess() override;

private:
bool m_isSlipRenderer;

std::vector<std::unique_ptr<ControlProxy>> m_pStemGain;
std::vector<std::unique_ptr<ControlProxy>> m_pStemMute;
std::vector<std::unique_ptr<PollingControlProxy>> m_pStemGain;
std::vector<std::unique_ptr<PollingControlProxy>> m_pStemMute;

void drawTexture(float x, float y, QOpenGLTexture* texture);
bool preprocessInner();

DISALLOW_COPY_AND_ASSIGN(WaveformRendererStem);
};
Loading