Skip to content

Commit

Permalink
feat: add rendergraph support for stem renderer
Browse files Browse the repository at this point in the history
  • Loading branch information
acolombier committed Oct 21, 2024
1 parent 358f66a commit f8033d0
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 76 deletions.
120 changes: 61 additions & 59 deletions src/waveform/renderers/allshader/waveformrendererstem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,17 @@
#include <QImage>
#include <QOpenGLTexture>


#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/rgbdata.h"
#include "waveform/renderers/waveformwidgetrenderer.h"
#include "waveform/waveform.h"

using namespace rendergraph;

namespace {
constexpr int kMaxSupportedStems = 4;
} // anonymous namespace
Expand All @@ -21,64 +26,81 @@ WaveformRendererStem::WaveformRendererStem(
::WaveformRendererAbstract::PositionSource type)
: WaveformRendererSignalBase(waveformWidget),
m_isSlipRenderer(type == ::WaveformRendererAbstract::Slip) {
initForRectangles<RGBAMaterial>(0);
setUsePreprocess(true);
}

void WaveformRendererStem::onSetup(const QDomNode& node) {
Q_UNUSED(node);
}

void WaveformRendererStem::initializeGL() {
m_shader.init();
m_textureShader.init();
auto group = m_pEQEnabled->getKey().group;
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;
}

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 warning on line 103 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 @@ -89,14 +111,14 @@ void WaveformRendererStem::paintGL() {

// 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 @@ -107,22 +129,22 @@ void WaveformRendererStem::paintGL() {

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 < 4; stemIdx++) {
// Stem is drawn twice with different opacity level, this allow to
// see the maximum signal by transparency
Expand All @@ -139,7 +161,7 @@ void WaveformRendererStem::paintGL() {
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 @@ -164,43 +186,23 @@ void WaveformRendererStem::paintGL() {
}

// 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; // TODO = m_waveformRenderer->getMatrix(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 "rendergraph/geometrynode.h"
#include "util/class.h"
#include "waveform/renderers/allshader/rgbadata.h"
#include "waveform/renderers/allshader/vertexdata.h"
#include "control/pollingcontrolproxy.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;
}

// 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);
};

0 comments on commit f8033d0

Please sign in to comment.