Skip to content

Commit

Permalink
also show time / beats since last marker, wip
Browse files Browse the repository at this point in the history
  • Loading branch information
m0dB authored and m0dB committed Nov 2, 2024
1 parent bbc8a11 commit f98154e
Show file tree
Hide file tree
Showing 4 changed files with 143 additions and 57 deletions.
15 changes: 15 additions & 0 deletions src/waveform/renderers/allshader/digitsrenderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,21 @@ void allshader::DigitsRenderer::updateTexture(
m_texture.setData(image);
}

float allshader::DigitsRenderer::textWidth(const QString& s) const {
const int n = s.length();

Check failure on line 209 in src/waveform/renderers/allshader/digitsrenderer.cpp

View workflow job for this annotation

GitHub Actions / clazy

unused variable 'n' [-Werror,-Wunused-variable]

Check failure on line 209 in src/waveform/renderers/allshader/digitsrenderer.cpp

View workflow job for this annotation

GitHub Actions / Ubuntu 22.04

unused variable ‘n’ [-Werror=unused-variable]

Check warning on line 209 in src/waveform/renderers/allshader/digitsrenderer.cpp

View workflow job for this annotation

GitHub Actions / coverage

unused variable ‘n’ [-Wunused-variable]

Check failure on line 209 in src/waveform/renderers/allshader/digitsrenderer.cpp

View workflow job for this annotation

GitHub Actions / macOS 12 x64

unused variable 'n' [-Werror,-Wunused-variable]

Check failure on line 209 in src/waveform/renderers/allshader/digitsrenderer.cpp

View workflow job for this annotation

GitHub Actions / macOS 12 arm64

unused variable 'n' [-Werror,-Wunused-variable]
const float space = static_cast<float>(m_penWidth) / 2;
float x = 0;

for (QChar c : s) {
if (x != 0) {
x -= space;
}
int index = charToIndex(c);
x += m_width[index];
}
return x;
}

float allshader::DigitsRenderer::draw(const QMatrix4x4& matrix,
float x,
float y,
Expand Down
1 change: 1 addition & 0 deletions src/waveform/renderers/allshader/digitsrenderer.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ class allshader::DigitsRenderer : public QOpenGLFunctions {
float y,
const QString& s);
float height() const;
float textWidth(const QString& s) const;

private:
mixxx::TextureShader m_shader;
Expand Down
159 changes: 108 additions & 51 deletions src/waveform/renderers/allshader/waveformrendermark.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <QOpenGLTexture>
#include <QPainterPath>

#include "track/beats.h"
#include "track/track.h"
#include "util/colorcomponents.h"
#include "waveform/renderers/allshader/matrixforwidgetgeometry.h"
Expand Down Expand Up @@ -62,13 +63,14 @@ allshader::WaveformRenderMark::WaveformRenderMark(
WaveformWidgetRenderer* waveformWidget,
::WaveformRendererAbstract::PositionSource type)
: ::WaveformRenderMarkBase(waveformWidget, false),
m_beatsUntilMark(0),
m_timeUntilMark(0.0),
m_pTimeElapsedControl(nullptr),
m_pTimeRemainingControl(nullptr),
m_isSlipRenderer(type == ::WaveformRendererAbstract::Slip) {
}

bool allshader::WaveformRenderMark::init() {
m_pTimeElapsedControl = std::make_unique<ControlProxy>(
m_waveformRenderer->getGroup(), "time_elapsed");
m_pTimeRemainingControl = std::make_unique<ControlProxy>(
m_waveformRenderer->getGroup(), "time_remaining");
return true;
Expand Down Expand Up @@ -208,6 +210,7 @@ void allshader::WaveformRenderMark::paintGL() {
QMatrix4x4 matrix = matrixForWidgetGeometry(m_waveformRenderer, false);

const double playPosition = m_waveformRenderer->getTruePosSample();
double prevMarkPosition = std::numeric_limits<double>::min();
double nextMarkPosition = std::numeric_limits<double>::max();

for (const auto& pMark : std::as_const(m_marks)) {
Expand Down Expand Up @@ -238,6 +241,11 @@ void allshader::WaveformRenderMark::paintGL() {
samplePosition < nextMarkPosition) {
nextMarkPosition = samplePosition;
}
if (pMark->isShowUntilNext() &&
samplePosition <= playPosition - 1.0 &&
samplePosition > prevMarkPosition) {
prevMarkPosition = samplePosition;
}
const double sampleEndPosition = pMark->getSampleEndPosition();

// Pixmaps are expected to have the mark stroke at the center,
Expand Down Expand Up @@ -305,14 +313,46 @@ void allshader::WaveformRenderMark::paintGL() {
drawTexture(matrix, drawOffset, 0.f, &m_playPosMarkTexture);
}

TrackPointer trackInfo = m_waveformRenderer->getTrackInfo();

if (!trackInfo) {
return;
}

mixxx::BeatsPointer trackBeats = trackInfo->getBeats();
if (!trackBeats) {
return;
}

auto itCurrentBeat = trackBeats->iteratorFrom(
mixxx::audio::FramePos::fromEngineSamplePos(playPosition));

if (std::abs(itCurrentBeat->toEngineSamplePos() - playPosition) >= 1.0) {
itCurrentBeat--;
}

if (WaveformWidgetFactory::instance()->getUntilMarkShowBeats() ||
WaveformWidgetFactory::instance()->getUntilMarkShowTime()) {
Distance distance = distanceUntilMark(
trackBeats, itCurrentBeat, playPosition, nextMarkPosition);
drawDistance(matrix, currentMarkPoint + 20, Qt::AlignRight, distance);
}
if (WaveformWidgetFactory::instance()->getUntilMarkShowBeats() ||
WaveformWidgetFactory::instance()->getUntilMarkShowTime()) {
updateUntilMark(playPosition, nextMarkPosition);
drawUntilMark(matrix, currentMarkPoint + 20);
Distance distance = distanceSinceMark(
trackBeats, itCurrentBeat, playPosition, prevMarkPosition);
drawDistance(matrix, currentMarkPoint - 20, Qt::AlignLeft, distance);
}
}

void allshader::WaveformRenderMark::drawUntilMark(const QMatrix4x4& matrix, float x) {
void allshader::WaveformRenderMark::drawDistance(const QMatrix4x4& matrix,
float x,
Qt::Alignment align,
const Distance& distance) {
if (distance.m_time == 0.0) {
return;
}

const bool untilMarkShowBeats = WaveformWidgetFactory::instance()->getUntilMarkShowBeats();
const bool untilMarkShowTime = WaveformWidgetFactory::instance()->getUntilMarkShowTime();
const auto untilMarkAlign = WaveformWidgetFactory::instance()->getUntilMarkAlign();
Expand All @@ -323,9 +363,6 @@ void allshader::WaveformRenderMark::drawUntilMark(const QMatrix4x4& matrix, floa
getMaxHeightForText(),
m_waveformRenderer->getDevicePixelRatio());

if (m_timeUntilMark == 0.0) {
return;
}
const float ch = m_digitsRenderer.height();

float y = untilMarkAlign == Qt::AlignTop ? 0.f
Expand All @@ -347,22 +384,24 @@ void allshader::WaveformRenderMark::drawUntilMark(const QMatrix4x4& matrix, floa
}

if (untilMarkShowBeats) {
const auto s = QString::number(distance.m_beats);
const auto w = m_digitsRenderer.draw(matrix,
x,
align == Qt::AlignLeft ? x - m_digitsRenderer.textWidth(s) : x,
y,
QString::number(m_beatsUntilMark));
s);
if (multiLine) {
y += ch;
} else {
x += w + ch * 0.75f;
x += align == Qt::AlignLeft ? -w - ch * 0.75 : w + ch * 0.75f;

Check warning on line 395 in src/waveform/renderers/allshader/waveformrendermark.cpp

View workflow job for this annotation

GitHub Actions / coverage

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

if (untilMarkShowTime) {
const auto s = timeSecToString(distance.m_time);
m_digitsRenderer.draw(matrix,
x,
align == Qt::AlignLeft ? x - m_digitsRenderer.textWidth(s) : x,
y,
timeSecToString(m_timeUntilMark));
s);
}
}

Expand Down Expand Up @@ -458,59 +497,77 @@ void allshader::WaveformRenderMark::updateMarkImage(WaveformMarkPointer pMark) {
pMark->generateImage(m_waveformRenderer->getDevicePixelRatio()));
}

void allshader::WaveformRenderMark::updateUntilMark(
double playPosition, double nextMarkPosition) {
m_beatsUntilMark = 0;
m_timeUntilMark = 0.0;
if (nextMarkPosition == std::numeric_limits<double>::max()) {
return;
allshader::WaveformRenderMark::Distance
allshader::WaveformRenderMark::distanceSinceMark(mixxx::BeatsPointer trackBeats,
mixxx::Beats::ConstIterator itCurrentBeat,

Check failure on line 502 in src/waveform/renderers/allshader/waveformrendermark.cpp

View workflow job for this annotation

GitHub Actions / clazy

Missing reference on large type (sizeof mixxx::class Beats::ConstIterator is 32 bytes) [-Wclazy-function-args-by-ref]
double playPosition,
double markPosition) {
Distance result{};

if (markPosition == std::numeric_limits<double>::min()) {
return result;
}

TrackPointer trackInfo = m_waveformRenderer->getTrackInfo();
auto itMarkBeat = trackBeats->iteratorFrom(
mixxx::audio::FramePos::fromEngineSamplePos(markPosition));

if (!trackInfo) {
return;
// itMarkBeat is the beat at or before the markPosition.
if (itMarkBeat->toEngineSamplePos() < markPosition) {
// if itMarkBeat is before markPosition, the next beat might be closer
// and it the one we are interested in
if ((itMarkBeat + 1)->toEngineSamplePos() - markPosition <
markPosition - itMarkBeat->toEngineSamplePos()) {
itMarkBeat++;
}
}

const double endPosition = m_waveformRenderer->getTrackSamples();
const double remainingTime = m_pTimeRemainingControl->get();
const double elapsedTime = m_pTimeElapsedControl->get();

mixxx::BeatsPointer trackBeats = trackInfo->getBeats();
if (!trackBeats) {
return;
// As playPosition corresponds with elapsedTime,
// we calculate the proportional part of playPosition - markPosition
result.m_beats = std::distance(itMarkBeat, itCurrentBeat);
result.m_time = std::max(0.0,
elapsedTime * (playPosition - markPosition) /
playPosition);

return result;
}

allshader::WaveformRenderMark::Distance
allshader::WaveformRenderMark::distanceUntilMark(mixxx::BeatsPointer trackBeats,
mixxx::Beats::ConstIterator itCurrentBeat,

Check failure on line 538 in src/waveform/renderers/allshader/waveformrendermark.cpp

View workflow job for this annotation

GitHub Actions / clazy

Missing reference on large type (sizeof mixxx::class Beats::ConstIterator is 32 bytes) [-Wclazy-function-args-by-ref]
double playPosition,
double markPosition) {
Distance result{};

if (markPosition == std::numeric_limits<double>::max()) {
return result;
}

auto itA = trackBeats->iteratorFrom(
mixxx::audio::FramePos::fromEngineSamplePos(playPosition));
auto itB = trackBeats->iteratorFrom(
mixxx::audio::FramePos::fromEngineSamplePos(nextMarkPosition));
auto itMarkBeat = trackBeats->iteratorFrom(
mixxx::audio::FramePos::fromEngineSamplePos(markPosition));

// itB is the beat at or after the nextMarkPosition.
if (itB->toEngineSamplePos() > nextMarkPosition) {
// if itB is after nextMarkPosition, the previous beat might be closer
// itMarkBeat is the beat at or after the markPosition.
if (itMarkBeat->toEngineSamplePos() > markPosition) {
// if itMarkBeat is after markPosition, the previous beat might be closer
// and it the one we are interested in
if (nextMarkPosition - (itB - 1)->toEngineSamplePos() <
itB->toEngineSamplePos() - nextMarkPosition) {
itB--;
if (markPosition - (itMarkBeat - 1)->toEngineSamplePos() <
itMarkBeat->toEngineSamplePos() - markPosition) {
itMarkBeat--;
}
}

if (std::abs(itA->toEngineSamplePos() - playPosition) < 1) {
m_currentBeatPosition = itA->toEngineSamplePos();
m_beatsUntilMark = std::distance(itA, itB);
itA++;
m_nextBeatPosition = itA->toEngineSamplePos();
} else {
m_nextBeatPosition = itA->toEngineSamplePos();
itA--;
m_currentBeatPosition = itA->toEngineSamplePos();
m_beatsUntilMark = std::distance(itA, itB);
}
const double remainingTime = m_pTimeRemainingControl->get();
const double endPosition = m_waveformRenderer->getTrackSamples();

result.m_beats = std::distance(itCurrentBeat, itMarkBeat);
// As endPosition - playPosition corresponds with remainingTime,
// we calculate the proportional part of nextMarkPosition - playPosition
m_timeUntilMark = std::max(0.0,
remainingTime * (nextMarkPosition - playPosition) /
// we calculate the proportional part of markPosition - playPosition
result.m_time = std::max(0.0,
remainingTime * (markPosition - playPosition) /
(endPosition - playPosition));

return result;
}

float allshader::WaveformRenderMark::getMaxHeightForText() const {
Expand Down
25 changes: 19 additions & 6 deletions src/waveform/renderers/allshader/waveformrendermark.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

#include "shaders/rgbashader.h"
#include "shaders/textureshader.h"
#include "track/beats.h"
#include "util/opengltexture2d.h"
#include "waveform/renderers/allshader/digitsrenderer.h"
#include "waveform/renderers/allshader/waveformrendererabstract.h"
Expand Down Expand Up @@ -40,6 +41,11 @@ class allshader::WaveformRenderMark : public ::WaveformRenderMarkBase,
void resizeGL(int w, int h) override;

private:
struct Distance {
int m_beats;
double m_time;
};

void updateMarkImage(WaveformMarkPointer pMark) override;

void updatePlayPosMarkTexture();
Expand All @@ -52,18 +58,25 @@ class allshader::WaveformRenderMark : public ::WaveformRenderMarkBase,

void drawMark(const QMatrix4x4& matrix, const QRectF& rect, QColor color);
void drawTexture(const QMatrix4x4& matrix, float x, float y, QOpenGLTexture* texture);
void updateUntilMark(double playPosition, double markerPosition);
void drawUntilMark(const QMatrix4x4& matrix, float x);
Distance distanceSinceMark(mixxx::BeatsPointer trackBeats,
mixxx::Beats::ConstIterator itCurrentBeat,
double playPosition,
double prevMarkPosition);
Distance distanceUntilMark(mixxx::BeatsPointer trackBeats,
mixxx::Beats::ConstIterator itCurrentBeat,
double playPosition,
double prevMarkPosition);
void drawDistance(const QMatrix4x4& matrix,
float x,
Qt::Alignment align,
const Distance& distance);
float getMaxHeightForText() const;

mixxx::RGBAShader m_rgbaShader;
mixxx::TextureShader m_textureShader;
OpenGLTexture2D m_playPosMarkTexture;
DigitsRenderer m_digitsRenderer;
int m_beatsUntilMark;
double m_timeUntilMark;
double m_currentBeatPosition;
double m_nextBeatPosition;
std::unique_ptr<ControlProxy> m_pTimeElapsedControl;
std::unique_ptr<ControlProxy> m_pTimeRemainingControl;

bool m_isSlipRenderer;
Expand Down

0 comments on commit f98154e

Please sign in to comment.