diff --git a/src/audiowrapper.h b/src/audiowrapper.h --- a/src/audiowrapper.h +++ b/src/audiowrapper.h @@ -78,8 +78,21 @@ WRITE setAudioRole NOTIFY audioRoleChanged) + Q_PROPERTY(ReplayGainSetting replayGainMode + READ replayGainMode + WRITE setReplayGainMode + NOTIFY replayGainModeChanged) + public: + enum ReplayGainSetting { + NoReplayGain, + ReplayGainAlbum, + ReplayGainTrack, + }; + + Q_ENUM(ReplayGainSetting) + explicit AudioWrapper(QObject *parent = nullptr); ~AudioWrapper() override; @@ -104,6 +117,8 @@ QAudio::Role audioRole() const; + ReplayGainSetting replayGainMode() const; + Q_SIGNALS: void mutedChanged(bool muted); @@ -134,6 +149,8 @@ void audioRoleChanged(); + void replayGainModeChanged(); + public Q_SLOTS: void setMuted(bool muted); @@ -158,6 +175,8 @@ void setAudioRole(QAudio::Role audioRole); + void setReplayGainMode(AudioWrapper::ReplayGainSetting mode); + private Q_SLOTS: void mediaStatusChanged(); @@ -187,6 +206,8 @@ void playerSeekableSignalChanges(bool isSeekable); + void resetVlcLayer(); + friend class AudioWrapperPrivate; std::unique_ptr d; diff --git a/src/audiowrapper_libvlc.cpp b/src/audiowrapper_libvlc.cpp --- a/src/audiowrapper_libvlc.cpp +++ b/src/audiowrapper_libvlc.cpp @@ -76,6 +76,8 @@ bool mHasSavedPosition = false; + AudioWrapper::ReplayGainSetting mReplayGainMode = AudioWrapper::NoReplayGain; + void vlcEventCallback(const struct libvlc_event_t *p_event); void mediaIsEnded(); @@ -106,33 +108,7 @@ AudioWrapper::AudioWrapper(QObject *parent) : QObject(parent), d(std::make_unique()) { d->mParent = this; - d->mInstance = libvlc_new(0, nullptr); - libvlc_set_user_agent(d->mInstance, "elisa", "Elisa Music Player"); - libvlc_set_app_id(d->mInstance, "org.kde.elisa", ELISA_VERSION_STRING, "elisa"); - - d->mPlayer = libvlc_media_player_new(d->mInstance); - - if (!d->mPlayer) { - qCDebug(orgKdeElisaPlayerVlc) << "AudioWrapper::AudioWrapper" << "failed creating player" << libvlc_errmsg(); - return; - } - - d->mPlayerEventManager = libvlc_media_player_event_manager(d->mPlayer); - - libvlc_event_attach(d->mPlayerEventManager, libvlc_MediaPlayerOpening, &vlc_callback, d.get()); - libvlc_event_attach(d->mPlayerEventManager, libvlc_MediaPlayerBuffering, &vlc_callback, d.get()); - libvlc_event_attach(d->mPlayerEventManager, libvlc_MediaPlayerPlaying, &vlc_callback, d.get()); - libvlc_event_attach(d->mPlayerEventManager, libvlc_MediaPlayerPaused, &vlc_callback, d.get()); - libvlc_event_attach(d->mPlayerEventManager, libvlc_MediaPlayerStopped, &vlc_callback, d.get()); - libvlc_event_attach(d->mPlayerEventManager, libvlc_MediaPlayerEndReached, &vlc_callback, d.get()); - libvlc_event_attach(d->mPlayerEventManager, libvlc_MediaPlayerEncounteredError, &vlc_callback, d.get()); - libvlc_event_attach(d->mPlayerEventManager, libvlc_MediaPlayerPositionChanged, &vlc_callback, d.get()); - libvlc_event_attach(d->mPlayerEventManager, libvlc_MediaPlayerSeekableChanged, &vlc_callback, d.get()); - libvlc_event_attach(d->mPlayerEventManager, libvlc_MediaPlayerLengthChanged, &vlc_callback, d.get()); - libvlc_event_attach(d->mPlayerEventManager, libvlc_MediaPlayerMuted, &vlc_callback, d.get()); - libvlc_event_attach(d->mPlayerEventManager, libvlc_MediaPlayerUnmuted, &vlc_callback, d.get()); - libvlc_event_attach(d->mPlayerEventManager, libvlc_MediaPlayerAudioVolume, &vlc_callback, d.get()); - libvlc_event_attach(d->mPlayerEventManager, libvlc_MediaPlayerAudioDevice, &vlc_callback, d.get()); + resetVlcLayer(); } AudioWrapper::~AudioWrapper() @@ -202,6 +178,11 @@ return {}/*d->mPlayer.audioRole()*/; } +AudioWrapper::ReplayGainSetting AudioWrapper::replayGainMode() const +{ + return d->mReplayGainMode; +} + QMediaPlayer::State AudioWrapper::playbackState() const { return d->mPreviousPlayerState; @@ -233,26 +214,30 @@ void AudioWrapper::setSource(const QUrl &source) { + resetVlcLayer(); + if (source.isLocalFile()) { qCDebug(orgKdeElisaPlayerVlc) << "AudioWrapper::setSource reading local resource"; d->mMedia = libvlc_media_new_path(d->mInstance, QDir::toNativeSeparators(source.toLocalFile()).toUtf8().constData()); + + if (!d->mMedia) { + qCDebug(orgKdeElisaPlayerVlc) << "AudioWrapper::setSource" + << "failed creating media" + << libvlc_errmsg() + << QDir::toNativeSeparators(source.toLocalFile()).toUtf8().constData(); + + return; + } } else { qCDebug(orgKdeElisaPlayerVlc) << "AudioWrapper::setSource reading remote resource"; d->mMedia = libvlc_media_new_location(d->mInstance, source.url().toUtf8().constData()); - } - - if (!d->mMedia) { - qCDebug(orgKdeElisaPlayerVlc) << "AudioWrapper::setSource" - << "failed creating media" - << libvlc_errmsg() - << QDir::toNativeSeparators(source.toLocalFile()).toUtf8().constData(); - d->mMedia = libvlc_media_new_path(d->mInstance, QDir::toNativeSeparators(source.toLocalFile()).toLatin1().constData()); if (!d->mMedia) { qCDebug(orgKdeElisaPlayerVlc) << "AudioWrapper::setSource" - << "failed creating media" - << libvlc_errmsg() - << QDir::toNativeSeparators(source.toLocalFile()).toLatin1().constData(); + << "failed creating media" + << libvlc_errmsg() + << source.url().toUtf8().constData(); + return; } } @@ -340,6 +325,17 @@ // d->mPlayer.setAudioRole(audioRole); } +void AudioWrapper::setReplayGainMode(AudioWrapper::ReplayGainSetting mode) +{ + if (d->mReplayGainMode == mode) { + return; + } + + d->mReplayGainMode = mode; + + Q_EMIT replayGainModeChanged(); +} + void AudioWrapper::mediaStatusChanged() { } @@ -413,6 +409,71 @@ QMetaObject::invokeMethod(this, [this, isSeekable]() {Q_EMIT seekableChanged(isSeekable);}, Qt::QueuedConnection); } +void AudioWrapper::resetVlcLayer() +{ + if (d->mInstance) { + libvlc_release(d->mInstance); + d->mInstance = nullptr; + } + + if (d->mPlayer) { + libvlc_media_player_release(d->mPlayer); + d->mPlayer = nullptr; + d->mPlayerEventManager = nullptr; + } + + switch (d->mReplayGainMode) + { + case NoReplayGain: + d->mInstance = libvlc_new(0, nullptr); + break; + case ReplayGainAlbum: + { + const char *arguments[] = {"--audio-replay-gain-mode=album"}; + d->mInstance = libvlc_new(1, arguments); + break; + } + case ReplayGainTrack: + { + const char *arguments[] = {"--audio-replay-gain-mode=track"}; + d->mInstance = libvlc_new(1, arguments); + break; + } + } + + if (!d->mInstance) { + qDebug() << "AudioWrapper::AudioWrapper" << "failed creating libvlc instance" << libvlc_errmsg(); + return; + } + + libvlc_set_user_agent(d->mInstance, "elisa", "Elisa Music Player"); + libvlc_set_app_id(d->mInstance, "org.kde.elisa", "0.3.80", "elisa"); + + d->mPlayer = libvlc_media_player_new(d->mInstance); + + if (!d->mPlayer) { + qDebug() << "AudioWrapper::AudioWrapper" << "failed creating player" << libvlc_errmsg(); + return; + } + + d->mPlayerEventManager = libvlc_media_player_event_manager(d->mPlayer); + + libvlc_event_attach(d->mPlayerEventManager, libvlc_MediaPlayerOpening, &vlc_callback, d.get()); + libvlc_event_attach(d->mPlayerEventManager, libvlc_MediaPlayerBuffering, &vlc_callback, d.get()); + libvlc_event_attach(d->mPlayerEventManager, libvlc_MediaPlayerPlaying, &vlc_callback, d.get()); + libvlc_event_attach(d->mPlayerEventManager, libvlc_MediaPlayerPaused, &vlc_callback, d.get()); + libvlc_event_attach(d->mPlayerEventManager, libvlc_MediaPlayerStopped, &vlc_callback, d.get()); + libvlc_event_attach(d->mPlayerEventManager, libvlc_MediaPlayerEndReached, &vlc_callback, d.get()); + libvlc_event_attach(d->mPlayerEventManager, libvlc_MediaPlayerEncounteredError, &vlc_callback, d.get()); + libvlc_event_attach(d->mPlayerEventManager, libvlc_MediaPlayerPositionChanged, &vlc_callback, d.get()); + libvlc_event_attach(d->mPlayerEventManager, libvlc_MediaPlayerSeekableChanged, &vlc_callback, d.get()); + libvlc_event_attach(d->mPlayerEventManager, libvlc_MediaPlayerLengthChanged, &vlc_callback, d.get()); + libvlc_event_attach(d->mPlayerEventManager, libvlc_MediaPlayerMuted, &vlc_callback, d.get()); + libvlc_event_attach(d->mPlayerEventManager, libvlc_MediaPlayerUnmuted, &vlc_callback, d.get()); + libvlc_event_attach(d->mPlayerEventManager, libvlc_MediaPlayerAudioVolume, &vlc_callback, d.get()); + libvlc_event_attach(d->mPlayerEventManager, libvlc_MediaPlayerAudioDevice, &vlc_callback, d.get()); +} + void AudioWrapperPrivate::vlcEventCallback(const struct libvlc_event_t *p_event) { const auto eventType = static_cast(p_event->type); diff --git a/src/filescanner.cpp b/src/filescanner.cpp --- a/src/filescanner.cpp +++ b/src/filescanner.cpp @@ -204,6 +204,12 @@ case KFileMetaData::Property::Rating: trackData.setRating(value.toInt()); break; + case KFileMetaData::Property::ReplayGainAlbumGain: + trackData.setReplayGainAlbumGain(value.toString()); + break; + case KFileMetaData::Property::ReplayGainTrackGain: + trackData.setReplayGainTrackGain(value.toString()); + break; default: break; } diff --git a/src/musicaudiotrack.h b/src/musicaudiotrack.h --- a/src/musicaudiotrack.h +++ b/src/musicaudiotrack.h @@ -185,6 +185,15 @@ bool hasEmbeddedCover() const; + void setReplayGainAlbumGain(const QString &value); + + QString replayGainAlbumGain() const; + + void setReplayGainTrackGain(const QString &value); + + QString replayGainTrackGain() const; + + TrackDataType toTrackData() const; private: diff --git a/src/musicaudiotrack.cpp b/src/musicaudiotrack.cpp --- a/src/musicaudiotrack.cpp +++ b/src/musicaudiotrack.cpp @@ -110,6 +110,10 @@ bool mSampleRateIsValid = false; + QString mReplayGainAlbumGain; + + QString mReplayGainTrackGain; + }; MusicAudioTrack::MusicAudioTrack() : d(new MusicAudioTrackPrivate()) @@ -517,6 +521,26 @@ return d->mHasBooleanCover; } +void MusicAudioTrack::setReplayGainAlbumGain(const QString &value) +{ + d->mReplayGainAlbumGain = value; +} + +QString MusicAudioTrack::replayGainAlbumGain() const +{ + return d->mReplayGainAlbumGain; +} + +void MusicAudioTrack::setReplayGainTrackGain(const QString &value) +{ + d->mReplayGainTrackGain = value; +} + +QString MusicAudioTrack::replayGainTrackGain() const +{ + return d->mReplayGainTrackGain; +} + MusicAudioTrack::TrackDataType MusicAudioTrack::toTrackData() const { auto result = MusicAudioTrack::TrackDataType{};