forked from mixxxdj/mixxx
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
added simple qopengl waveform renderer
- Loading branch information
Showing
11 changed files
with
328 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
181 changes: 181 additions & 0 deletions
181
src/waveform/renderers/qopengl/waveformrenderersimple.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,181 @@ | ||
#include "waveform/renderers/qopengl/waveformrenderersimple.h" | ||
|
||
#include "track/track.h" | ||
#include "util/math.h" | ||
#include "waveform/renderers/qopengl/calculatematrix.h" | ||
#include "waveform/waveform.h" | ||
#include "waveform/waveformwidgetfactory.h" | ||
#include "waveform/widgets/qopengl/waveformwidget.h" | ||
#include "widget/wskincolor.h" | ||
#include "widget/wwidget.h" | ||
|
||
using namespace qopengl; | ||
|
||
WaveformRendererSimple::WaveformRendererSimple( | ||
WaveformWidgetRenderer* waveformWidget) | ||
: WaveformRendererSignalBase(waveformWidget) { | ||
} | ||
|
||
WaveformRendererSimple::~WaveformRendererSimple() { | ||
} | ||
|
||
void WaveformRendererSimple::onSetup(const QDomNode& node) { | ||
Q_UNUSED(node); | ||
} | ||
|
||
void WaveformRendererSimple::initializeGL() { | ||
m_shader.init(); | ||
} | ||
|
||
void WaveformRendererSimple::renderGL() { | ||
TrackPointer pTrack = m_waveformRenderer->getTrackInfo(); | ||
if (!pTrack) { | ||
return; | ||
} | ||
|
||
ConstWaveformPointer waveform = pTrack->getWaveform(); | ||
if (waveform.isNull()) { | ||
return; | ||
} | ||
|
||
const int dataSize = waveform->getDataSize(); | ||
if (dataSize <= 1) { | ||
return; | ||
} | ||
|
||
const WaveformData* data = waveform->data(); | ||
if (data == nullptr) { | ||
return; | ||
} | ||
|
||
const float devicePixelRatio = m_waveformRenderer->getDevicePixelRatio(); | ||
const int length = static_cast<int>(m_waveformRenderer->getLength() * devicePixelRatio); | ||
|
||
// Not multiplying with devicePixelRatio will also work. In that case, on | ||
// High-DPI-Display the lines will be devicePixelRatio pixels wide (which is | ||
// also what is used for the beat grid and the markers), or in other words | ||
// each block of samples is represented by devicePixelRatio pixels (width). | ||
|
||
const double firstVisualIndex = m_waveformRenderer->getFirstDisplayedPosition() * dataSize; | ||
const double lastVisualIndex = m_waveformRenderer->getLastDisplayedPosition() * dataSize; | ||
|
||
// Represents the # of waveform data points per horizontal pixel. | ||
const double visualIncrementPerPixel = | ||
(lastVisualIndex - firstVisualIndex) / static_cast<double>(length); | ||
|
||
// 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]); | ||
|
||
const float breadth = static_cast<float>(m_waveformRenderer->getBreadth()) * devicePixelRatio; | ||
const float halfBreadth = breadth / 2.0f; | ||
|
||
const float heightFactor = allGain * halfBreadth / 255.f; | ||
|
||
// Effective visual index of x | ||
double xVisualSampleIndex = firstVisualIndex; | ||
|
||
const int numVerticesPerLine = 6; // 2 triangles | ||
|
||
int reserved[2]; | ||
|
||
reserved[0] = numVerticesPerLine * length; | ||
m_vertices[0].clear(); | ||
m_vertices[0].reserve(reserved[0]); | ||
|
||
// the horizontal line | ||
reserved[1] = numVerticesPerLine; | ||
m_vertices[1].clear(); | ||
m_vertices[1].reserve(reserved[1]); | ||
|
||
m_vertices[1].addRectangle( | ||
0.f, | ||
halfBreadth - 0.5f * devicePixelRatio, | ||
static_cast<float>(length), | ||
halfBreadth + 0.5f * devicePixelRatio); | ||
|
||
for (int pos = 0; pos < length; ++pos) { | ||
// Our current pixel (x) corresponds to a number of visual samples | ||
// (visualSamplerPerPixel) in our waveform object. We take the max of | ||
// all the data points on either side of xVisualSampleIndex within a | ||
// window of 'maxSamplingRange' visual samples to measure the maximum | ||
// data point contained by this pixel. | ||
double maxSamplingRange = visualIncrementPerPixel / 2.0; | ||
|
||
// Since xVisualSampleIndex is in visual-samples (e.g. R,L,R,L) we want | ||
// to check +/- maxSamplingRange frames, not samples. To do this, divide | ||
// xVisualSampleIndex by 2. Since frames indices are integers, we round | ||
// to the nearest integer by adding 0.5 before casting to int. | ||
int visualFrameStart = int(xVisualSampleIndex / 2.0 - maxSamplingRange + 0.5); | ||
int visualFrameStop = int(xVisualSampleIndex / 2.0 + maxSamplingRange + 0.5); | ||
const int lastVisualFrame = dataSize / 2 - 1; | ||
|
||
// We now know that some subset of [visualFrameStart, visualFrameStop] | ||
// lies within the valid range of visual frames. Clamp | ||
// visualFrameStart/Stop to within [0, lastVisualFrame]. | ||
visualFrameStart = math_clamp(visualFrameStart, 0, lastVisualFrame); | ||
visualFrameStop = math_clamp(visualFrameStop, 0, lastVisualFrame); | ||
|
||
int visualIndexStart = visualFrameStart * 2; | ||
int visualIndexStop = visualFrameStop * 2; | ||
|
||
visualIndexStart = std::max(visualIndexStart, 0); | ||
visualIndexStop = std::min(visualIndexStop, dataSize); | ||
|
||
// 2 channels | ||
float max[2]{}; | ||
|
||
for (int i = visualIndexStart; i < visualIndexStop; i += 2) { | ||
for (int chn = 0; chn < 2; chn++) { | ||
const WaveformData& waveformData = data[i + chn]; | ||
const float filteredAll = static_cast<float>(waveformData.filtered.all); | ||
|
||
max[chn] = math_max(max[chn], filteredAll); | ||
} | ||
} | ||
|
||
const float fpos = static_cast<float>(pos); | ||
|
||
// lines are thin rectangles | ||
m_vertices[0].addRectangle( | ||
fpos - 0.5f, | ||
halfBreadth - heightFactor * max[0], | ||
fpos + 0.5f, | ||
halfBreadth + heightFactor * max[1]); | ||
|
||
xVisualSampleIndex += visualIncrementPerPixel; | ||
} | ||
|
||
const QMatrix4x4 matrix = calculateMatrix(m_waveformRenderer, true); | ||
|
||
const int matrixLocation = m_shader.uniformLocation("matrix"); | ||
const int colorLocation = m_shader.uniformLocation("color"); | ||
const int positionLocation = m_shader.attributeLocation("position"); | ||
|
||
m_shader.bind(); | ||
m_shader.enableAttributeArray(positionLocation); | ||
|
||
m_shader.setUniformValue(matrixLocation, matrix); | ||
|
||
QColor colors[2]; | ||
colors[0].setRgbF(static_cast<float>(m_signalColor_r), | ||
static_cast<float>(m_signalColor_g), | ||
static_cast<float>(m_signalColor_b)); | ||
colors[1].setRgbF(static_cast<float>(m_axesColor_r), | ||
static_cast<float>(m_axesColor_g), | ||
static_cast<float>(m_axesColor_b), | ||
static_cast<float>(m_axesColor_a)); | ||
|
||
for (int i = 0; i < 2; i++) { | ||
DEBUG_ASSERT(reserved[i] == m_vertices[i].size()); | ||
m_shader.setUniformValue(colorLocation, colors[i]); | ||
m_shader.setAttributeArray( | ||
positionLocation, GL_FLOAT, m_vertices[i].constData(), 2); | ||
|
||
glDrawArrays(GL_TRIANGLES, 0, m_vertices[i].size()); | ||
} | ||
|
||
m_shader.disableAttributeArray(positionLocation); | ||
m_shader.release(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
#pragma once | ||
|
||
#include "util/class.h" | ||
#include "waveform/renderers/qopengl/shaders/unicolorshader.h" | ||
#include "waveform/renderers/qopengl/vertexdata.h" | ||
#include "waveform/renderers/qopengl/waveformrenderersignalbase.h" | ||
|
||
namespace qopengl { | ||
class WaveformRendererSimple; | ||
} | ||
|
||
class qopengl::WaveformRendererSimple final : public qopengl::WaveformRendererSignalBase { | ||
public: | ||
explicit WaveformRendererSimple(WaveformWidgetRenderer* waveformWidget); | ||
~WaveformRendererSimple() override; | ||
|
||
// override ::WaveformRendererSignalBase | ||
void onSetup(const QDomNode& node) override; | ||
|
||
void initializeGL() override; | ||
void renderGL() override; | ||
|
||
private: | ||
UnicolorShader m_shader; | ||
VertexData m_vertices[2]; | ||
|
||
DISALLOW_COPY_AND_ASSIGN(WaveformRendererSimple); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
#include "waveform/widgets/qopengl/simplewaveformwidget.h" | ||
|
||
#include "waveform/renderers/qopengl/waveformrenderbackground.h" | ||
#include "waveform/renderers/qopengl/waveformrenderbeat.h" | ||
#include "waveform/renderers/qopengl/waveformrendererendoftrack.h" | ||
#include "waveform/renderers/qopengl/waveformrendererpreroll.h" | ||
#include "waveform/renderers/qopengl/waveformrenderersimple.h" | ||
#include "waveform/renderers/qopengl/waveformrendermark.h" | ||
#include "waveform/renderers/qopengl/waveformrendermarkrange.h" | ||
#include "waveform/widgets/qopengl/moc_simplewaveformwidget.cpp" | ||
|
||
using namespace qopengl; | ||
|
||
SimpleWaveformWidget::SimpleWaveformWidget(const QString& group, QWidget* parent) | ||
: WaveformWidget(group, parent) { | ||
addRenderer<WaveformRenderBackground>(); | ||
addRenderer<WaveformRendererEndOfTrack>(); | ||
addRenderer<WaveformRendererPreroll>(); | ||
addRenderer<WaveformRenderMarkRange>(); | ||
addRenderer<WaveformRendererSimple>(); | ||
addRenderer<WaveformRenderBeat>(); | ||
addRenderer<WaveformRenderMark>(); | ||
|
||
m_initSuccess = init(); | ||
} | ||
|
||
SimpleWaveformWidget::~SimpleWaveformWidget() { | ||
} | ||
|
||
void SimpleWaveformWidget::castToQWidget() { | ||
m_widget = this; | ||
} | ||
|
||
void SimpleWaveformWidget::paintEvent(QPaintEvent* event) { | ||
Q_UNUSED(event); | ||
} |
Oops, something went wrong.