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

Create JavascriptPlayerProxy #14314

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
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1582,6 +1582,8 @@ add_library(
src/widget/wwidget.cpp
src/widget/wwidgetgroup.cpp
src/widget/wwidgetstack.cpp
src/controllers/scripting/javascriptplayerproxy.cpp
src/controllers/scripting/javascriptplayerproxy.h
)
set(MIXXX_COMMON_PRECOMPILED_HEADER src/util/assert.h)
set(
Expand Down
220 changes: 220 additions & 0 deletions src/controllers/scripting/javascriptplayerproxy.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,220 @@
#include "javascriptplayerproxy.h"

#include "moc_javascriptplayerproxy.cpp"

JavascriptPlayerProxy::JavascriptPlayerProxy(BaseTrackPlayer* pTrackPlayer, QObject* parent)
: QObject(parent),
m_pTrackPlayer(pTrackPlayer) {
connect(m_pTrackPlayer,
&BaseTrackPlayer::loadingTrack,
this,
&JavascriptPlayerProxy::slotLoadingTrack);
connect(m_pTrackPlayer,
&BaseTrackPlayer::newTrackLoaded,
this,
&JavascriptPlayerProxy::slotTrackLoaded);
connect(m_pTrackPlayer,
&BaseTrackPlayer::playerEmpty,
this,
&JavascriptPlayerProxy::trackUnloaded);
connect(this,
&JavascriptPlayerProxy::trackChanged,
this,
&JavascriptPlayerProxy::slotTrackChanged);
if (m_pTrackPlayer && m_pTrackPlayer->getLoadedTrack()) {
slotTrackLoaded(pTrackPlayer->getLoadedTrack());
}
}

void JavascriptPlayerProxy::slotTrackLoaded(TrackPointer pTrack) {
m_pCurrentTrack = pTrack;
if (pTrack != nullptr) {
connect(pTrack.get(),
&Track::artistChanged,
this,
&JavascriptPlayerProxy::artistChanged);
connect(pTrack.get(),
&Track::titleChanged,
this,
&JavascriptPlayerProxy::titleChanged);
connect(pTrack.get(),
&Track::albumChanged,
this,
&JavascriptPlayerProxy::albumChanged);
connect(pTrack.get(),
&Track::albumArtistChanged,
this,
&JavascriptPlayerProxy::albumArtistChanged);
connect(pTrack.get(),
&Track::genreChanged,
this,
&JavascriptPlayerProxy::genreChanged);
connect(pTrack.get(),
&Track::composerChanged,
this,
&JavascriptPlayerProxy::composerChanged);
connect(pTrack.get(),
&Track::groupingChanged,
this,
&JavascriptPlayerProxy::groupingChanged);
connect(pTrack.get(),
&Track::yearChanged,
this,
&JavascriptPlayerProxy::yearChanged);
connect(pTrack.get(),
&Track::trackNumberChanged,
this,
&JavascriptPlayerProxy::trackNumberChanged);
connect(pTrack.get(),
&Track::trackTotalChanged,
this,
&JavascriptPlayerProxy::trackTotalChanged);
subclassesSlotTrackLoaded();
slotWaveformChanged();
}
emit trackChanged();
emit trackLoaded();
}

void JavascriptPlayerProxy::slotLoadingTrack(TrackPointer pNewTrack, TrackPointer pOldTrack) {
VERIFY_OR_DEBUG_ASSERT(pOldTrack == m_pCurrentTrack) {
qWarning() << "QML Player proxy was expected to contain "
<< pOldTrack.get() << "as active track but got"
<< m_pCurrentTrack.get();
}

if (pNewTrack.get() == m_pCurrentTrack.get()) {
emit trackLoading();
return;
}

const TrackPointer pTrack = m_pCurrentTrack;
if (pTrack != nullptr) {
disconnect(pTrack.get(), nullptr, this, nullptr);
}
m_pCurrentTrack.reset();
m_pCurrentTrack = pNewTrack;
m_waveformTexture = QImage();
emit trackChanged();
emit trackLoading();
}

void JavascriptPlayerProxy::slotTrackChanged() {
emit artistChanged();
emit titleChanged();
emit albumChanged();
emit albumArtistChanged();
emit genreChanged();
emit composerChanged();
emit groupingChanged();
emit yearChanged();
emit trackNumberChanged();
emit trackTotalChanged();

emit waveformLengthChanged();
emit waveformTextureChanged();
emit waveformTextureSizeChanged();
emit waveformTextureStrideChanged();

subclassesSlotTrackChanged();
}

void JavascriptPlayerProxy::slotWaveformChanged() {
emit waveformLengthChanged();
emit waveformTextureSizeChanged();
emit waveformTextureStrideChanged();

const TrackPointer pTrack = m_pCurrentTrack;
if (!pTrack) {
return;
}
const ConstWaveformPointer pWaveform =
pTrack->getWaveform();
if (!pWaveform) {
return;
}
const int textureWidth = pWaveform->getTextureStride();
const int textureHeight = pWaveform->getTextureSize() / pWaveform->getTextureStride();

const WaveformData* data = pWaveform->data();
// Make a copy of the waveform data, stripping the stems portion. Note that the datasize is
// different from the texture size -- we want the full texture size so the upload works. See
// m_data in waveform/waveform.h.
m_waveformData.resize(pWaveform->getTextureSize());
for (int i = 0; i < pWaveform->getDataSize(); i++) {
m_waveformData[i] = data[i].filtered;
}

m_waveformTexture =
QImage(reinterpret_cast<const uchar*>(m_waveformData.data()),
textureWidth,
textureHeight,
QImage::Format_RGBA8888);
DEBUG_ASSERT(!m_waveformTexture.isNull());
emit waveformTextureChanged();
}

int JavascriptPlayerProxy::getWaveformLength() const {
const TrackPointer pTrack = m_pCurrentTrack;
if (pTrack) {
const ConstWaveformPointer pWaveform = pTrack->getWaveform();
if (pWaveform) {
return pWaveform->getDataSize();
}
}
return 0;
}

QString JavascriptPlayerProxy::getWaveformTexture() const {
if (m_waveformTexture.isNull()) {
return QString();
}
QByteArray byteArray;
QBuffer buffer(&byteArray);
buffer.open(QIODevice::WriteOnly);
m_waveformTexture.save(&buffer, "png");

QString imageData = QString::fromLatin1(byteArray.toBase64().data());
if (imageData.isEmpty()) {
return QString();
}

return QStringLiteral("data:image/png;base64,") + imageData;
}

int JavascriptPlayerProxy::getWaveformTextureSize() const {
const TrackPointer pTrack = m_pCurrentTrack;
if (pTrack) {
const ConstWaveformPointer pWaveform = pTrack->getWaveform();
if (pWaveform) {
return pWaveform->getTextureSize();
}
}
return 0;
}

int JavascriptPlayerProxy::getWaveformTextureStride() const {
const TrackPointer pTrack = m_pCurrentTrack;
if (pTrack) {
const ConstWaveformPointer pWaveform = pTrack->getWaveform();
if (pWaveform) {
return pWaveform->getTextureStride();
}
}
return 0;
}

bool JavascriptPlayerProxy::isLoaded() const {
return m_pCurrentTrack != nullptr;
}

PROPERTY_IMPL_GETTER(JavascriptPlayerProxy, QString, artist, getArtist)
PROPERTY_IMPL_GETTER(JavascriptPlayerProxy, QString, title, getTitle)
PROPERTY_IMPL_GETTER(JavascriptPlayerProxy, QString, album, getAlbum)
PROPERTY_IMPL_GETTER(JavascriptPlayerProxy, QString, albumArtist, getAlbumArtist)
PROPERTY_IMPL_GETTER(JavascriptPlayerProxy, QString, genre, getGenre)
PROPERTY_IMPL_GETTER(JavascriptPlayerProxy, QString, composer, getComposer)
PROPERTY_IMPL_GETTER(JavascriptPlayerProxy, QString, grouping, getGrouping)
PROPERTY_IMPL_GETTER(JavascriptPlayerProxy, QString, year, getYear)
PROPERTY_IMPL_GETTER(JavascriptPlayerProxy, QString, trackNumber, getTrackNumber)
PROPERTY_IMPL_GETTER(JavascriptPlayerProxy, QString, trackTotal, getTrackTotal)
96 changes: 96 additions & 0 deletions src/controllers/scripting/javascriptplayerproxy.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
#pragma once

#include <QBuffer>

#include "mixer/basetrackplayer.h"
#include "track/track.h"
#include "waveform/waveform.h"

#define PROPERTY_IMPL_GETTER(NAMESPACE, TYPE, NAME, GETTER) \
TYPE NAMESPACE::GETTER() const { \
const TrackPointer pTrack = m_pCurrentTrack; \
if (pTrack == nullptr) { \
return TYPE(); \
} \
return pTrack->GETTER(); \
}

class JavascriptPlayerProxy : public QObject {
Q_OBJECT
Q_PROPERTY(bool isLoaded READ isLoaded NOTIFY trackChanged)
Q_PROPERTY(QString artist READ getArtist NOTIFY artistChanged)
Q_PROPERTY(QString title READ getTitle NOTIFY titleChanged)
Q_PROPERTY(QString album READ getAlbum NOTIFY albumChanged)
Q_PROPERTY(QString albumArtist READ getAlbumArtist NOTIFY albumArtistChanged)
Q_PROPERTY(QString genre READ getGenre STORED false NOTIFY genreChanged)
Q_PROPERTY(QString composer READ getComposer NOTIFY composerChanged)
Q_PROPERTY(QString grouping READ getGrouping NOTIFY groupingChanged)
Q_PROPERTY(QString year READ getYear NOTIFY yearChanged)
Q_PROPERTY(QString trackNumber READ getTrackNumber NOTIFY trackNumberChanged)
Q_PROPERTY(QString trackTotal READ getTrackTotal NOTIFY trackTotalChanged)

Q_PROPERTY(int waveformLength READ getWaveformLength NOTIFY waveformLengthChanged)
Q_PROPERTY(QString waveformTexture READ getWaveformTexture NOTIFY waveformTextureChanged)
Q_PROPERTY(int waveformTextureSize READ getWaveformTextureSize NOTIFY
waveformTextureSizeChanged)
Q_PROPERTY(int waveformTextureStride READ getWaveformTextureStride NOTIFY
waveformTextureStrideChanged)

public:
explicit JavascriptPlayerProxy(BaseTrackPlayer* pTrackPlayer, QObject* parent);

bool isLoaded() const;
QString getTitle() const;
QString getArtist() const;
QString getAlbum() const;
QString getAlbumArtist() const;
QString getGenre() const;
QString getComposer() const;
QString getGrouping() const;
QString getYear() const;
QString getTrackNumber() const;
QString getTrackTotal() const;

int getWaveformLength() const;
QString getWaveformTexture() const;
int getWaveformTextureSize() const;
int getWaveformTextureStride() const;

public slots:
void slotTrackLoaded(TrackPointer pTrack);
void slotLoadingTrack(TrackPointer pNewTrack, TrackPointer pOldTrack);
void slotTrackChanged();
void slotWaveformChanged();

signals:
void trackLoading();
void trackLoaded();
void trackUnloaded();
void trackChanged();

void albumChanged();
void titleChanged();
void artistChanged();
void albumArtistChanged();
void genreChanged();
void composerChanged();
void groupingChanged();
void yearChanged();
void trackNumberChanged();
void trackTotalChanged();

void waveformLengthChanged();
void waveformTextureChanged();
void waveformTextureSizeChanged();
void waveformTextureStrideChanged();

protected:
virtual void subclassesSlotTrackLoaded() {
}
virtual void subclassesSlotTrackChanged() {
}
std::vector<WaveformFilteredData> m_waveformData;
QImage m_waveformTexture;
QPointer<BaseTrackPlayer> m_pTrackPlayer;
TrackPointer m_pCurrentTrack;
};
Loading
Loading