diff --git a/src/UI/DocumentViews/AudioVisualizer/TimingAxis.cc b/src/UI/DocumentViews/AudioVisualizer/TimingAxis.cc index 668c618299670cb94bc097c918381ffec4e97598..6f69f07c9f7e3d80ab53bec1267b4ed49b439533 100644 --- a/src/UI/DocumentViews/AudioVisualizer/TimingAxis.cc +++ b/src/UI/DocumentViews/AudioVisualizer/TimingAxis.cc @@ -16,11 +16,8 @@ using namespace Vivy; -TimingAxis::TimingAxis(AudioContext::StreamPtr stream, int height_, int width_) noexcept +TimingAxis::TimingAxis() noexcept : QGraphicsObject() - , audioStream(stream) - , height(height_) - , width(width_) { pen = QPen(axisColour); pen.setWidth(penWidth); @@ -30,7 +27,8 @@ TimingAxis::TimingAxis(AudioContext::StreamPtr stream, int height_, int width_) QRectF TimingAxis::boundingRect() const { - return QRectF(0, penWidth, width + 2 * penWidth, -height - penWidth); + return QRectF(0, penWidth, TimingUtils::audioWidth() + 2 * penWidth, + -TimingUtils::axisHeight() - penWidth); } /* @@ -42,7 +40,8 @@ TimingAxis::refreshTicks() { int nbAvailableTicks = availableTicks.size(); int minorTicksIndex = 0; - int length{ int(audioStream->getLength()) }; + int length = TimingUtils::audioLength(); + int width = TimingUtils::audioWidth(); if (width != 0 && length != 0) { for (minorTicksIndex = 0; minorTicksIndex < nbAvailableTicks; minorTicksIndex++) { if (width * availableTicks[minorTicksIndex] / length >= minBetweenMinor) { @@ -65,8 +64,8 @@ TimingAxis::refreshTicks() void TimingAxis::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { - int audioLength; - if ((audioLength = int(audioStream->getLength())) == 0) + int audioLength = TimingUtils::audioLength(); + if (audioLength == 0) return; int yText = -majorTicksHeight - timeDigitsMargin; @@ -83,13 +82,13 @@ TimingAxis::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWi * should look whether this precision loss is negligible or not */ for (int i = 0; i < audioLength; i += majorTicks) { - int pos = TimingUtils::posFromMs(i, width, audioLength); + int pos = TimingUtils::posFromMs(i); painter->drawText(QPoint(pos, yText), TimingUtils::printMajorTicks(i)); painter->drawLine(pos, 0, pos, -majorTicksHeight); } if (minorTicks > 0) { for (int i = 0; i < audioLength; i += minorTicks) { - int pos = TimingUtils::posFromMs(i, width, audioLength); + int pos = TimingUtils::posFromMs(i); if (Q_LIKELY(fmod(i, majorTicks) != 0)) painter->drawLine(pos, 0, pos, -minorTicksHeight); } diff --git a/src/UI/DocumentViews/AudioVisualizer/TimingAxis.hh b/src/UI/DocumentViews/AudioVisualizer/TimingAxis.hh index 243468ac98537f0777c7db5c5c3e83e4dcdb17d7..13235d96ba67a301833473b2e632c150a44aece6 100644 --- a/src/UI/DocumentViews/AudioVisualizer/TimingAxis.hh +++ b/src/UI/DocumentViews/AudioVisualizer/TimingAxis.hh @@ -20,7 +20,7 @@ class TimingAxis final : public QGraphicsObject { Q_OBJECT public: - explicit TimingAxis(AudioContext::StreamPtr stream, int height, int width) noexcept; + explicit TimingAxis() noexcept; ~TimingAxis() noexcept override = default; QRectF boundingRect() const override; @@ -31,10 +31,6 @@ private: QPen pen; int penWidth{ 1 }; - AudioContext::StreamPtr audioStream; - int height{ 30 }; - int width{ 0 }; - /* * We use ints here because * qPainter->drawLine() and qPainter->drawText() diff --git a/src/UI/DocumentViews/AudioVisualizer/TimingCursor.cc b/src/UI/DocumentViews/AudioVisualizer/TimingCursor.cc index 349a1f1e852cb8d2754ac14730763a1994e8a5b9..28b5d4116b99b495e8a0c6f1f2342e609b15aa7c 100644 --- a/src/UI/DocumentViews/AudioVisualizer/TimingCursor.cc +++ b/src/UI/DocumentViews/AudioVisualizer/TimingCursor.cc @@ -7,23 +7,23 @@ using namespace Vivy; -TimingCursor::TimingCursor(int height_, QGraphicsItem *parent) - : QGraphicsItem(parent) - , height(height_) +TimingCursor::TimingCursor() + : QGraphicsItem() { - textRect = QRectF(0, 10, maxWidth, height - 20); // TODO : remove 10/20 magic numbers + textRect = QRectF(0, 10, maxWidth, + TimingUtils::audioHeight() - 20); // TODO : remove 10/20 magic numbers } QRectF TimingCursor::boundingRect() const { - return QRectF(-maxWidth, 0, maxWidth * 2, height); + return QRectF(-maxWidth, 0, maxWidth * 2, TimingUtils::audioHeight()); } void TimingCursor::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { - painter->drawLine(0, 0, 0, height); + painter->drawLine(0, 0, 0, TimingUtils::audioHeight()); QRectF textRectangle = textRect; QPointF sceneLeft = mapFromScene(QPointF(0, 0)); diff --git a/src/UI/DocumentViews/AudioVisualizer/TimingCursor.hh b/src/UI/DocumentViews/AudioVisualizer/TimingCursor.hh index f9026bed4bbb4fb89c8c1eca5dc26f96dc1464df..bd0c765fa1474ba5490e7fa806ba90a45edb485e 100644 --- a/src/UI/DocumentViews/AudioVisualizer/TimingCursor.hh +++ b/src/UI/DocumentViews/AudioVisualizer/TimingCursor.hh @@ -6,7 +6,7 @@ namespace Vivy { class TimingCursor final : public QGraphicsItem { public: - explicit TimingCursor(int, QGraphicsItem *parent = nullptr); + explicit TimingCursor(); QRectF boundingRect() const override; void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override; diff --git a/src/UI/DocumentViews/AudioVisualizer/TimingScene.cc b/src/UI/DocumentViews/AudioVisualizer/TimingScene.cc index 383c4aab6fec7776ee9b7b2ae828296fb94221c5..78f5195eb2bc115036225fe4ad1ea351c9505286 100644 --- a/src/UI/DocumentViews/AudioVisualizer/TimingScene.cc +++ b/src/UI/DocumentViews/AudioVisualizer/TimingScene.cc @@ -52,22 +52,26 @@ TimingScene::rebuildScene() } // We put a common origin for the items at the bottom of the axis - int timingAxisHeight = 30; // TODO: remove magic number + TimingUtils::setAxisHeight(30); // TODO: remove magic number QPixmap pixmap(QPixmap::fromImage(img)); backgroundImg = addPixmap(pixmap); - backgroundImg->setPos(0, timingAxisHeight); + backgroundImg->setPos(0, TimingUtils::axisHeight()); - ax = new TimingAxis(audioStream, timingAxisHeight, pixmap.width()); + TimingUtils::setAudioHeight(pixmap.height()); + TimingUtils::setAudioWidth(img.width()); + TimingUtils::setAudioLength(audioStream->getLength()); + + ax = new TimingAxis(); addItem(ax); - ax->setPos(0, timingAxisHeight); + ax->setPos(0, TimingUtils::axisHeight()); // Freeze the scene boundaries setSceneRect(sceneRect()); - cursor = new TimingCursor(pixmap.height()); + cursor = new TimingCursor(); addItem(cursor); - cursor->setPos(0, timingAxisHeight); + cursor->setPos(0, TimingUtils::axisHeight()); if (auto assDocument = currentVivyDocument->getAssSubDocument()) { QVector<Ass::LinePtr> lines = assDocument->getLines(); @@ -101,8 +105,7 @@ TimingScene::mouseMoveEvent(QGraphicsSceneMouseEvent *mouseEvent) noexcept { int x = int(mouseEvent->scenePos().rx()); cursor->setPos(x, 30); - cursor->setTime(TimingUtils::printCursor( - TimingUtils::msFromPos(x, int(audioStream->getLength()), width()))); + cursor->setTime(TimingUtils::printCursor(TimingUtils::msFromPos(x))); QGraphicsScene::mouseMoveEvent(mouseEvent); } @@ -110,7 +113,7 @@ void TimingScene::handleMousePressEventLine(QGraphicsSceneMouseEvent *event, Ass::LinePtr p) noexcept { QPointF pos = event->scenePos(); - int time = timeFromPos(int(pos.x())); + int time = TimingUtils::msFromPos(int(pos.x())); if (const auto &btn = event->button(); btn == Qt::LeftButton) { p->setStart(quint64(time)); @@ -129,18 +132,6 @@ TimingScene::handleMousePressEventChar(QGraphicsSceneMouseEvent *, Ass::LinePtr) { } -int -TimingScene::timeFromPos(int x) const noexcept -{ - return TimingUtils::msFromPos(x, int(width()), int(audioStream->getLength())); -} - -int -TimingScene::posFromTime(int t) const noexcept -{ - return TimingUtils::posFromMs(t, int(width()), int(audioStream->getLength())); -} - QGraphicsPixmapItem * TimingScene::bg() noexcept { diff --git a/src/UI/DocumentViews/AudioVisualizer/TimingUtils.cc b/src/UI/DocumentViews/AudioVisualizer/TimingUtils.cc index 2e847ba2f1378aad0612fe4b411b60b523ef463e..7e710002c5ce47d9fd0826a2a41d1a9ce39da704 100644 --- a/src/UI/DocumentViews/AudioVisualizer/TimingUtils.cc +++ b/src/UI/DocumentViews/AudioVisualizer/TimingUtils.cc @@ -2,8 +2,40 @@ using namespace Vivy; -int TimingUtils::majorTicks{ 0 }; -int TimingUtils::minorTicks{ 0 }; +int TimingUtils::m_majorTicks{ 1 }; +int TimingUtils::m_minorTicks{ 1 }; + +int TimingUtils::m_axisHeight{ 1 }; +int TimingUtils::m_audioHeight{ 1 }; +int TimingUtils::m_audioWidth{ 1 }; +int TimingUtils::m_audioLength{ 1 }; + +qreal TimingUtils::m_wl{ 0 }; +qreal TimingUtils::m_lw{ 0 }; + +int +TimingUtils::posFromMs(int t) noexcept +{ + return int(t * m_wl); +} + +int +TimingUtils::posFromMs(int t, int audioWidth, int audioLength) noexcept +{ + return audioLength == 0 ? 0 : int(qint64(t) * qint64(audioWidth) / audioLength); +} + +int +TimingUtils::msFromPos(int x) noexcept +{ + return int(x * m_lw); +} + +int +TimingUtils::msFromPos(int x, int audioLength, int audioWidth) noexcept +{ + return audioWidth == 0 ? 0 : int(qint64(x) * qint64(audioLength) / audioWidth); +} void TimingUtils::adjustFlip(QRectF *rect, qreal left, qreal right) noexcept @@ -33,7 +65,7 @@ TimingUtils::printMajorTicks(int t) noexcept // TODO : adapt to different ticks (not everytime with "." first) QString ret( QStringLiteral("%1").arg(t % 60000 / 1000, t >= 60000 ? 2 : 1, 10, QLatin1Char('0')) + - QString(".") + QString::number(t % 1000 / majorTicks)); + QString(".") + QString::number(t % 1000 / m_majorTicks)); if (t >= 60000) ret.prepend(QString::number(t / 60000) + QString(":")); if (t >= 360000) @@ -47,10 +79,17 @@ TimingUtils::printCursor(int t) noexcept // TODO : adapt to different ticks (not everytime with "." first) QString ret( QStringLiteral("%1").arg(t % 60000 / 1000, t >= 60000 ? 2 : 1, 10, QLatin1Char('0')) + - QString(".") + QString::number(t % 1000 / minorTicks)); + QString(".") + QString::number(t % 1000 / m_minorTicks)); if (t >= 60000) ret.prepend(QString::number(t / 60000) + QString(":")); if (t >= 360000) ret.prepend(QString::number(t / 360000) + QString(":")); return ret; } + +void +TimingUtils::updateRatios() noexcept +{ + m_wl = m_audioLength != 0 ? qreal(m_audioWidth) / qreal(m_audioLength) : 0; + m_lw = m_audioWidth != 0 ? qreal(m_audioLength) / qreal(m_audioWidth) : 0; +} diff --git a/src/UI/DocumentViews/AudioVisualizer/TimingUtils.hh b/src/UI/DocumentViews/AudioVisualizer/TimingUtils.hh index 78d271bf924cd75241f8c149dcd95ae507d65111..1ff08ceb357a314855d491022eaa7396720906e2 100644 --- a/src/UI/DocumentViews/AudioVisualizer/TimingUtils.hh +++ b/src/UI/DocumentViews/AudioVisualizer/TimingUtils.hh @@ -9,33 +9,61 @@ #define getTimingScene() static_cast<TimingScene *>(scene()) +/* + * FIXME + * Relying on static may pose issues when multiple audioVisualiser + * are open (when multiple VivyDocuments are open) + * Solution : yeet the statics and put an instance of this class + * in the TimingScene + */ namespace Vivy { class TimingUtils { private: - static int majorTicks; - static int minorTicks; + // Managed by TimingAxis + static int m_majorTicks, m_minorTicks; + // Managed by TimingScene + static int m_axisHeight, m_audioWidth, m_audioLength, m_audioHeight; + // Self-managed + static qreal m_wl, m_lw; public: - static inline int posFromMs(int t, int audioWidth, int audioLength) noexcept - { - return audioLength == 0 ? 0 : int(qint64(t) * qint64(audioWidth) / audioLength); - } + static int posFromMs(int t, int audioWidth, int audioLength) noexcept; + static int posFromMs(int t) noexcept; - static inline int msFromPos(int x, int audioLength, int audioWidth) noexcept - { - return audioWidth == 0 ? 0 : int(qint64(x) * qint64(audioLength) / audioWidth); - } - - static inline void setTicks(int t, int T) noexcept - { - minorTicks = t; - majorTicks = T; - }; + static int msFromPos(int x, int audioLength, int audioWidth) noexcept; + static int msFromPos(int x) noexcept; static void adjustTranslate(QRectF *, qreal, qreal) noexcept; static void adjustFlip(QRectF *, qreal, qreal) noexcept; + static QString printMajorTicks(int) noexcept; static QString printCursor(int) noexcept; + + static inline void setTicks(int t, int T) noexcept + { + m_minorTicks = t; + m_majorTicks = T; + }; + static inline void setAxisHeight(int x) { m_axisHeight = x; }; + static inline void setAudioHeight(int x) { m_audioHeight = x; }; + static inline void setAudioWidth(int x) + { + m_audioWidth = x; + updateRatios(); + }; + static inline void setAudioLength(int x) + { + m_audioLength = x; + updateRatios(); + }; + + static inline int axisHeight() { return m_axisHeight; }; + static inline int audioHeight() { return m_audioHeight; }; + static inline int audioWidth() { return m_audioWidth; }; + static inline int audioLength() { return m_audioLength; }; + +private: + static void updateRatios() noexcept; }; }