WIP replaygain support
This commit is contained in:
@@ -164,6 +164,12 @@
|
|||||||
<message id="Lms.Settings.demo-cannot-save">Cannot save using a demo account!</message>
|
<message id="Lms.Settings.demo-cannot-save">Cannot save using a demo account!</message>
|
||||||
<message id="Lms.Settings.password-bad">Bad password</message>
|
<message id="Lms.Settings.password-bad">Bad password</message>
|
||||||
<message id="Lms.Settings.password-must-fill-old-password">Old password must be filled in</message>
|
<message id="Lms.Settings.password-must-fill-old-password">Old password must be filled in</message>
|
||||||
|
<message id="Lms.Settings.replaygain-mode">ReplayGain mode</message>
|
||||||
|
<message id="Lms.Settings.replaygain-mode.none">No ReplayGain</message>
|
||||||
|
<message id="Lms.Settings.replaygain-mode.auto">Auto</message>
|
||||||
|
<message id="Lms.Settings.replaygain-mode.track">Track</message>
|
||||||
|
<message id="Lms.Settings.replaygain-mode.release">Album</message>
|
||||||
|
<message id="Lms.Settings.replaygain-preamp">Replay gain preAmp</message>
|
||||||
<message id="Lms.Settings.subsonic-artist-list-mode">Artist list mode</message>
|
<message id="Lms.Settings.subsonic-artist-list-mode">Artist list mode</message>
|
||||||
<message id="Lms.Settings.subsonic-artist-list-mode.all-artists">All artists</message>
|
<message id="Lms.Settings.subsonic-artist-list-mode.all-artists">All artists</message>
|
||||||
<message id="Lms.Settings.subsonic-artist-list-mode.release-artists">Album artists</message>
|
<message id="Lms.Settings.subsonic-artist-list-mode.release-artists">Album artists</message>
|
||||||
|
|||||||
@@ -164,6 +164,12 @@
|
|||||||
<message id="Lms.Settings.demo-cannot-save">Impossible de sauvegarder en utilisant un compte de démo !</message>
|
<message id="Lms.Settings.demo-cannot-save">Impossible de sauvegarder en utilisant un compte de démo !</message>
|
||||||
<message id="Lms.Settings.password-bad">Mauvais mot de passe</message>
|
<message id="Lms.Settings.password-bad">Mauvais mot de passe</message>
|
||||||
<message id="Lms.Settings.password-must-fill-old-password">L'ancien mot de passe doit être renseigné</message>
|
<message id="Lms.Settings.password-must-fill-old-password">L'ancien mot de passe doit être renseigné</message>
|
||||||
|
<message id="Lms.Settings.replaygain-mode">Mode ReplayGain</message>
|
||||||
|
<message id="Lms.Settings.replaygain-mode.none">Pas de ReplayGain</message>
|
||||||
|
<message id="Lms.Settings.replaygain-mode.auto">Automatique</message>
|
||||||
|
<message id="Lms.Settings.replaygain-mode.track">Piste</message>
|
||||||
|
<message id="Lms.Settings.replaygain-mode.release">Album</message>
|
||||||
|
<message id="Lms.Settings.replaygain-preamp">PreAmplification ReplayGain</message>
|
||||||
<message id="Lms.Settings.subsonic-artist-list-mode">Mode de listage des artistes</message>
|
<message id="Lms.Settings.subsonic-artist-list-mode">Mode de listage des artistes</message>
|
||||||
<message id="Lms.Settings.subsonic-artist-list-mode.all-artists">Tous les artistes</message>
|
<message id="Lms.Settings.subsonic-artist-list-mode.all-artists">Tous les artistes</message>
|
||||||
<message id="Lms.Settings.subsonic-artist-list-mode.release-artists">Tous les artistes d'album</message>
|
<message id="Lms.Settings.subsonic-artist-list-mode.release-artists">Tous les artistes d'album</message>
|
||||||
@@ -188,4 +194,5 @@
|
|||||||
<message id="Wt.WMessageBox.Yes">Oui</message>
|
<message id="Wt.WMessageBox.Yes">Oui</message>
|
||||||
<message id="Wt.WMessageBox.No">Non</message>
|
<message id="Wt.WMessageBox.No">Non</message>
|
||||||
<message id="Wt.WValidator.Invalid">Ce champ ne peut pas être vide</message>
|
<message id="Wt.WValidator.Invalid">Ce champ ne peut pas être vide</message>
|
||||||
|
<message id="Wt.WDoubleValidator.BadRange">Le nombre doit être compris entre {1} et {2}</message>
|
||||||
</messages>
|
</messages>
|
||||||
|
|||||||
+143
-147
@@ -4,161 +4,157 @@
|
|||||||
<!--FORMS message blocks-->
|
<!--FORMS message blocks-->
|
||||||
|
|
||||||
<message id="Lms.Settings.template">
|
<message id="Lms.Settings.template">
|
||||||
<legend>${tr:Lms.Settings.appearance}</legend>
|
<div class="row">
|
||||||
<div class="form-horizontal">
|
<div class="col-lg-6">
|
||||||
<div class="form-group">
|
<legend>${tr:Lms.Settings.appearance}</legend>
|
||||||
<label class="col-sm-2 control-label" for="${id:dark-mode}">
|
<div class="form-horizontal">
|
||||||
${tr:Lms.Settings.dark-mode}
|
<div class="form-group">
|
||||||
</label>
|
<div class="col-lg-offset-3 col-lg-9">
|
||||||
<div class="col-sm-5">
|
<div class="checkbox">
|
||||||
<div class="checkbox"><label>${dark-mode}</label></div>
|
<label>${dark-mode}${tr:Lms.Settings.dark-mode}</label>
|
||||||
|
${dark-mode-info clas="help-block"}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-5 help-block">
|
<legend>${tr:Lms.Settings.audio}</legend>
|
||||||
${dark-mode-info}
|
<div class="alert alert-info">
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<legend>${tr:Lms.Settings.audio}</legend>
|
|
||||||
<div class="col-sm-12">
|
|
||||||
<div class="row">
|
|
||||||
<div class="alert alert-info col-sm-7">
|
|
||||||
${tr:Lms.Settings.audio-settings-are-local}
|
${tr:Lms.Settings.audio-settings-are-local}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="form-horizontal">
|
||||||
</div>
|
<div class="form-group">
|
||||||
<div class="form-horizontal">
|
<label class="col-lg-3 control-label" for="${id:transcode-mode}">
|
||||||
<div class="form-group">
|
${tr:Lms.Settings.transcode-mode}
|
||||||
<label class="col-sm-2 control-label" for="${id:transcode-mode}">
|
</label>
|
||||||
${tr:Lms.Settings.transcode-mode}
|
<div class="col-lg-9">
|
||||||
</label>
|
${transcode-mode}
|
||||||
<div class="col-sm-5">
|
${transcode-mode-info class="help-block"}
|
||||||
${transcode-mode}
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-5 help-block">
|
<div class="form-group">
|
||||||
${transcode-mode-info}
|
<label class="control-label col-lg-3" for="${id:transcode-format}">
|
||||||
</div>
|
${tr:Lms.Settings.transcode-format}
|
||||||
</div>
|
</label>
|
||||||
<div class="form-group">
|
<div class="col-lg-9">
|
||||||
<label class="control-label col-sm-2" for="${id:transcode-format}">
|
${transcode-format}
|
||||||
${tr:Lms.Settings.transcode-format}
|
${transcode-format-info class="help-block"}
|
||||||
</label>
|
</div>
|
||||||
<div class="col-sm-5">
|
</div>
|
||||||
${transcode-format}
|
<div class="form-group">
|
||||||
</div>
|
<label class="control-label col-lg-3" for="${id:transcode-bitrate}">
|
||||||
<div class="help-block col-sm-5">
|
${tr:Lms.Settings.transcode-bitrate}
|
||||||
${transcode-format-info}
|
</label>
|
||||||
</div>
|
<div class="col-lg-9">
|
||||||
</div>
|
<div class="input-group">
|
||||||
<div class="form-group">
|
${transcode-bitrate}
|
||||||
<label class="control-label col-sm-2" for="${id:transcode-bitrate}">
|
<span class="input-group-addon">kbps</span>
|
||||||
${tr:Lms.Settings.transcode-bitrate}
|
</div>
|
||||||
</label>
|
${transcode-bitrate-info class="help-block"}
|
||||||
<div class="col-sm-5">
|
</div>
|
||||||
<div class="input-group">
|
</div>
|
||||||
${transcode-bitrate}
|
|
||||||
<span class="input-group-addon">kbps</span>
|
<div class="form-group">
|
||||||
|
<label class="col-lg-3 control-label" for="${id:replaygain-mode}">
|
||||||
|
${tr:Lms.Settings.replaygain-mode}
|
||||||
|
</label>
|
||||||
|
<div class="col-lg-9">
|
||||||
|
${replaygain-mode}
|
||||||
|
${replaygain-mode-info class="help-block"}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-lg-3 control-label" for="${id:replaygain-preamp}">
|
||||||
|
${tr:Lms.Settings.replaygain-preamp}
|
||||||
|
</label>
|
||||||
|
<div class="col-lg-9">
|
||||||
|
<div class="input-group">
|
||||||
|
${replaygain-preamp}
|
||||||
|
<span class="input-group-addon">dB</span>
|
||||||
|
</div>
|
||||||
|
${replaygain-preamp-info class="help-block"}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="help-block col-sm-5">
|
${<if-has-subsonic-api>}
|
||||||
${transcode-bitrate-info}
|
<legend>${tr:Lms.Settings.subsonic-api}</legend>
|
||||||
</div>
|
<div class="form-horizontal">
|
||||||
</div>
|
<div class="form-group">
|
||||||
</div>
|
<div class="col-lg-offset-3 col-lg-9">
|
||||||
${<if-has-subsonic-api>}
|
<div class="checkbox">
|
||||||
<legend>${tr:Lms.Settings.subsonic-api}</legend>
|
<label>${subsonic-transcode-enable}${tr:Lms.Settings.transcode-enable}</label>
|
||||||
<div class="form-horizontal">
|
${subsonic-transcode-enable-info class="help-block"}
|
||||||
|
</div>
|
||||||
<div class="form-group">
|
</div>
|
||||||
<label class="col-sm-2 control-label" for="${id:subsonic-transcode-enable}">
|
</div>
|
||||||
${tr:Lms.Settings.transcode-enable}
|
<div class="form-group">
|
||||||
</label>
|
<label class="control-label col-lg-3" for="${id:subsonic-transcode-format}">
|
||||||
<div class="col-sm-5">
|
${tr:Lms.Settings.transcode-format}
|
||||||
<div class="checkbox"><label>${subsonic-transcode-enable}</label></div>
|
</label>
|
||||||
</div>
|
<div class="col-lg-9">
|
||||||
<div class="col-sm-5 help-block">
|
${subsonic-transcode-format}
|
||||||
${subsonic-transcode-enable-info}
|
${subsonic-transcode-format-info class="help-block"}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="control-label col-sm-2" for="${id:subsonic-transcode-format}">
|
<label class="control-label col-lg-3" for="${id:subsonic-transcode-bitrate}">
|
||||||
${tr:Lms.Settings.transcode-format}
|
${tr:Lms.Settings.transcode-bitrate}
|
||||||
</label>
|
</label>
|
||||||
<div class="col-sm-5">
|
<div class="col-lg-9">
|
||||||
${subsonic-transcode-format}
|
<div class="input-group">
|
||||||
</div>
|
${subsonic-transcode-bitrate}
|
||||||
<div class="col-sm-5 help-block">
|
<span class="input-group-addon">kbps</span>
|
||||||
${subsonic-transcode-format-info}
|
</div>
|
||||||
</div>
|
${subsonic-transcode-bitrate-info class="help-block"}
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
</div>
|
||||||
<label class="control-label col-sm-2" for="${id:subsonic-transcode-bitrate}">
|
<div class="form-group">
|
||||||
${tr:Lms.Settings.transcode-bitrate}
|
<label class="control-label col-lg-3" for="${id:subsonic-artist-list-mode}">
|
||||||
</label>
|
${tr:Lms.Settings.subsonic-artist-list-mode}
|
||||||
<div class="col-sm-5">
|
</label>
|
||||||
<div class="input-group">
|
<div class="col-lg-9">
|
||||||
${subsonic-transcode-bitrate}
|
${subsonic-artist-list-mode}
|
||||||
<span class="input-group-addon">kbps</span>
|
${subsonic-artist-list-mode-info class="help-block"}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="help-block col-sm-5">
|
${</if-has-subsonic-api>}
|
||||||
${subsonic-transcode-bitrate-info}
|
<legend>${tr:Lms.Settings.change-password}</legend>
|
||||||
</div>
|
<div class="form-horizontal">
|
||||||
</div>
|
${<if-has-old-password>}
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="control-label col-sm-2" for="${id:subsonic-artist-list-mode}">
|
<label class="control-label col-lg-3" for="${id:password-old}">
|
||||||
${tr:Lms.Settings.subsonic-artist-list-mode}
|
${tr:Lms.password-old}
|
||||||
</label>
|
</label>
|
||||||
<div class="col-sm-5">
|
<div class="col-lg-9">
|
||||||
${subsonic-artist-list-mode}
|
${password-old}
|
||||||
</div>
|
${password-old-info class="help-block"}
|
||||||
<div class="help-block col-sm-5">
|
</div>
|
||||||
${subsonic-artist-list-mode-info}
|
</div>
|
||||||
</div>
|
${</if-has-old-password>}
|
||||||
</div>
|
<div class="form-group">
|
||||||
|
<label class="control-label col-lg-3" for="${id:password}">
|
||||||
|
${tr:Lms.password-new}
|
||||||
|
</label>
|
||||||
|
<div class="col-lg-9">
|
||||||
|
${password}
|
||||||
|
${password-info class="help-block"}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label col-lg-3" for="${id:password-confirm}">
|
||||||
|
${tr:Lms.password-confirm}
|
||||||
|
</label>
|
||||||
|
<div class="col-lg-9">
|
||||||
|
${password-confirm}
|
||||||
|
${password-confirm-info class="help-block"}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
<div class="form-group">
|
||||||
${</if-has-subsonic-api>}
|
<div class="col-lg-offset-3 col-lg-9">
|
||||||
<legend>${tr:Lms.Settings.change-password}</legend>
|
${apply-btn class="btn-primary"} ${discard-btn}
|
||||||
<div class="form-horizontal">
|
</div>
|
||||||
${<if-has-old-password>}
|
</div>
|
||||||
<div class="form-group">
|
|
||||||
<label class="control-label col-sm-2" for="${id:password-old}">
|
|
||||||
${tr:Lms.password-old}
|
|
||||||
</label>
|
|
||||||
<div class="col-sm-5">
|
|
||||||
${password-old}
|
|
||||||
</div>
|
|
||||||
<div class="help-block col-sm-5">
|
|
||||||
${password-old-info}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
${</if-has-old-password>}
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="control-label col-sm-2" for="${id:password}">
|
|
||||||
${tr:Lms.password-new}
|
|
||||||
</label>
|
|
||||||
<div class="col-sm-5">
|
|
||||||
${password}
|
|
||||||
</div>
|
|
||||||
<div class="help-block col-sm-5">
|
|
||||||
${password-info}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="control-label col-sm-2" for="${id:password-confirm}">
|
|
||||||
${tr:Lms.password-confirm}
|
|
||||||
</label>
|
|
||||||
<div class="col-sm-5">
|
|
||||||
${password-confirm}
|
|
||||||
</div>
|
|
||||||
<div class="help-block col-sm-5">
|
|
||||||
${password-confirm-info}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group">
|
|
||||||
<div class="col-sm-offset-2 col-sm-10">
|
|
||||||
${apply-btn class="btn-primary"} ${discard-btn}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -121,6 +121,7 @@ LMS.mediaplayer = function () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var _setReplayGain = function (replayGain) {
|
var _setReplayGain = function (replayGain) {
|
||||||
|
console.log("Applying gain " + replayGain);
|
||||||
_gainNode.gain.value = Math.pow(10, (_settings.replayGain.preAmpGain + replayGain) / 20);
|
_gainNode.gain.value = Math.pow(10, (_settings.replayGain.preAmpGain + replayGain) / 20);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -86,8 +86,8 @@ LmsTheme::getStyleSheets(Database::User::UITheme theme)
|
|||||||
case Database::User::UITheme::Dark:
|
case Database::User::UITheme::Dark:
|
||||||
return
|
return
|
||||||
{
|
{
|
||||||
{"css/bootstrap-darkly.min.css"},
|
|
||||||
{"resources/themes/bootstrap/3/wt.css"},
|
{"resources/themes/bootstrap/3/wt.css"},
|
||||||
|
{"css/bootstrap-darkly.min.css"},
|
||||||
{"css/lms.css"},
|
{"css/lms.css"},
|
||||||
{"css/lms-darkly.css"},
|
{"css/lms-darkly.css"},
|
||||||
};
|
};
|
||||||
@@ -95,8 +95,8 @@ LmsTheme::getStyleSheets(Database::User::UITheme theme)
|
|||||||
case Database::User::UITheme::Light:
|
case Database::User::UITheme::Light:
|
||||||
return
|
return
|
||||||
{
|
{
|
||||||
{"css/bootstrap-flatly.min.css"},
|
|
||||||
{"resources/themes/bootstrap/3/wt.css"},
|
{"resources/themes/bootstrap/3/wt.css"},
|
||||||
|
{"css/bootstrap-flatly.min.css"},
|
||||||
{"css/lms.css"},
|
{"css/lms.css"},
|
||||||
{"css/lms-flatly.css"},
|
{"css/lms-flatly.css"},
|
||||||
};
|
};
|
||||||
|
|||||||
+53
-10
@@ -35,6 +35,7 @@
|
|||||||
#include "resource/AudioFileResource.hpp"
|
#include "resource/AudioFileResource.hpp"
|
||||||
|
|
||||||
#include "utils/String.hpp"
|
#include "utils/String.hpp"
|
||||||
|
#include "utils/Utils.hpp"
|
||||||
|
|
||||||
#include "LmsApplication.hpp"
|
#include "LmsApplication.hpp"
|
||||||
|
|
||||||
@@ -56,9 +57,8 @@ static std::string settingsToJSString(const MediaPlayer::Settings& settings)
|
|||||||
|
|
||||||
{
|
{
|
||||||
Json::Object replayGain;
|
Json::Object replayGain;
|
||||||
replayGain["mode"] = "TODO";
|
replayGain["mode"] = static_cast<int>(settings.replayGain.mode);
|
||||||
replayGain["preAmpGain"] = 0;
|
replayGain["preAmpGain"] = settings.replayGain.preAmpGain;
|
||||||
replayGain["clippingPreventionMode"] = "TODO";
|
|
||||||
res["replayGain"] = std::move(replayGain);
|
res["replayGain"] = std::move(replayGain);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,7 +67,7 @@ static std::string settingsToJSString(const MediaPlayer::Settings& settings)
|
|||||||
|
|
||||||
static
|
static
|
||||||
std::optional<MediaPlayer::Settings::Transcode::Mode>
|
std::optional<MediaPlayer::Settings::Transcode::Mode>
|
||||||
modeFromString(const std::string& str)
|
transcodeModeFromString(const std::string& str)
|
||||||
{
|
{
|
||||||
const auto value {StringUtils::readAs<int>(str)};
|
const auto value {StringUtils::readAs<int>(str)};
|
||||||
if (!value)
|
if (!value)
|
||||||
@@ -121,6 +121,38 @@ bitrateFromString(const std::string& str)
|
|||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
std::optional<MediaPlayer::Settings::ReplayGain::Mode>
|
||||||
|
replayGainModeFromString(const std::string& str)
|
||||||
|
{
|
||||||
|
const auto value {StringUtils::readAs<int>(str)};
|
||||||
|
if (!value)
|
||||||
|
return std::nullopt;
|
||||||
|
|
||||||
|
MediaPlayer::Settings::ReplayGain::Mode mode {static_cast<MediaPlayer::Settings::ReplayGain::Mode>(*value)};
|
||||||
|
switch (mode)
|
||||||
|
{
|
||||||
|
case MediaPlayer::Settings::ReplayGain::Mode::None:
|
||||||
|
case MediaPlayer::Settings::ReplayGain::Mode::Auto:
|
||||||
|
case MediaPlayer::Settings::ReplayGain::Mode::Track:
|
||||||
|
case MediaPlayer::Settings::ReplayGain::Mode::Release:
|
||||||
|
return mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
std::optional<float>
|
||||||
|
replayGainPreAmpGainFromString(const std::string& str)
|
||||||
|
{
|
||||||
|
const auto value {StringUtils::readAs<double>(str)};
|
||||||
|
if (!value)
|
||||||
|
return std::nullopt;
|
||||||
|
|
||||||
|
return clamp(*value, (double)MediaPlayer::Settings::ReplayGain::minPreAmpGain, (double)MediaPlayer::Settings::ReplayGain::maxPreAmpGain);
|
||||||
|
}
|
||||||
|
|
||||||
static MediaPlayer::Settings settingsfromJSString(const std::string& strSettings)
|
static MediaPlayer::Settings settingsfromJSString(const std::string& strSettings)
|
||||||
{
|
{
|
||||||
using Settings = MediaPlayer::Settings;
|
using Settings = MediaPlayer::Settings;
|
||||||
@@ -131,13 +163,24 @@ static MediaPlayer::Settings settingsfromJSString(const std::string& strSettings
|
|||||||
|
|
||||||
MediaPlayer::Settings settings;
|
MediaPlayer::Settings settings;
|
||||||
|
|
||||||
const Json::Value transcodeValue {parsedSettings.get("transcode")};
|
|
||||||
if (transcodeValue.type() == Json::Type::Object)
|
|
||||||
{
|
{
|
||||||
const Json::Object transcode {transcodeValue};
|
const Json::Value transcodeValue {parsedSettings.get("transcode")};
|
||||||
settings.transcode.mode = modeFromString(transcode.get("mode").toString().orIfNull("")).value_or(Settings::Transcode::defaultMode);
|
if (transcodeValue.type() == Json::Type::Object)
|
||||||
settings.transcode.format = formatFromString(transcode.get("format").toString().orIfNull("")).value_or(Settings::Transcode::defaultFormat);
|
{
|
||||||
settings.transcode.bitrate = bitrateFromString(transcode.get("bitrate").toString().orIfNull("")).value_or(Settings::Transcode::defaultBitrate);
|
const Json::Object transcode {transcodeValue};
|
||||||
|
settings.transcode.mode = transcodeModeFromString(transcode.get("mode").toString().orIfNull("")).value_or(Settings::Transcode::defaultMode);
|
||||||
|
settings.transcode.format = formatFromString(transcode.get("format").toString().orIfNull("")).value_or(Settings::Transcode::defaultFormat);
|
||||||
|
settings.transcode.bitrate = bitrateFromString(transcode.get("bitrate").toString().orIfNull("")).value_or(Settings::Transcode::defaultBitrate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const Json::Value replayGainValue {parsedSettings.get("replayGain")};
|
||||||
|
if (replayGainValue.type() == Json::Type::Object)
|
||||||
|
{
|
||||||
|
const Json::Object replayGain {replayGainValue};
|
||||||
|
settings.replayGain.mode = replayGainModeFromString(replayGain.get("mode").toString().orIfNull("")).value_or(Settings::ReplayGain::defaultMode);
|
||||||
|
settings.replayGain.preAmpGain = replayGainPreAmpGainFromString(replayGain.get("preAmpGain").toString().orIfNull("")).value_or(Settings::ReplayGain::defaultPreAmpGain);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return settings;
|
return settings;
|
||||||
|
|||||||
@@ -76,6 +76,8 @@ class MediaPlayer : public Wt::WTemplate
|
|||||||
|
|
||||||
static inline constexpr Mode defaultMode {Mode::None};
|
static inline constexpr Mode defaultMode {Mode::None};
|
||||||
static inline constexpr Gain defaultPreAmpGain {};
|
static inline constexpr Gain defaultPreAmpGain {};
|
||||||
|
static inline constexpr Gain minPreAmpGain {-15};
|
||||||
|
static inline constexpr Gain maxPreAmpGain {15};
|
||||||
static inline constexpr ClippingPreventionMode defaultClippingPreventionMode {ClippingPreventionMode::None};
|
static inline constexpr ClippingPreventionMode defaultClippingPreventionMode {ClippingPreventionMode::None};
|
||||||
|
|
||||||
Mode mode;
|
Mode mode;
|
||||||
|
|||||||
@@ -136,8 +136,13 @@ PlayQueue::PlayQueue()
|
|||||||
|
|
||||||
if (!LmsApp->getUser()->isDemo())
|
if (!LmsApp->getUser()->isDemo())
|
||||||
{
|
{
|
||||||
LmsApp->post([=]
|
LmsApp->getMediaPlayer()->settingsLoaded.connect([=]
|
||||||
{
|
{
|
||||||
|
if (_mediaPlayerSettingsLoaded)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_mediaPlayerSettingsLoaded = true;
|
||||||
|
|
||||||
std::size_t trackPos {};
|
std::size_t trackPos {};
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -81,6 +81,7 @@ class PlayQueue : public Wt::WTemplate
|
|||||||
|
|
||||||
bool _repeatAll {};
|
bool _repeatAll {};
|
||||||
bool _radioMode {};
|
bool _radioMode {};
|
||||||
|
bool _mediaPlayerSettingsLoaded {};
|
||||||
Database::IdType _tracklistId {};
|
Database::IdType _tracklistId {};
|
||||||
Wt::WContainerWidget* _entriesContainer {};
|
Wt::WContainerWidget* _entriesContainer {};
|
||||||
Wt::WPushButton* _showMore {};
|
Wt::WPushButton* _showMore {};
|
||||||
|
|||||||
@@ -21,6 +21,8 @@
|
|||||||
|
|
||||||
#include <Wt/WCheckBox.h>
|
#include <Wt/WCheckBox.h>
|
||||||
#include <Wt/WComboBox.h>
|
#include <Wt/WComboBox.h>
|
||||||
|
#include <Wt/WDoubleValidator.h>
|
||||||
|
#include <Wt/WDoubleSpinBox.h>
|
||||||
#include <Wt/WFormModel.h>
|
#include <Wt/WFormModel.h>
|
||||||
#include <Wt/WLineEdit.h>
|
#include <Wt/WLineEdit.h>
|
||||||
#include <Wt/WPushButton.h>
|
#include <Wt/WPushButton.h>
|
||||||
@@ -51,6 +53,8 @@ class SettingsModel : public Wt::WFormModel
|
|||||||
static inline const Field TranscodeModeField {"transcode-mode"};
|
static inline const Field TranscodeModeField {"transcode-mode"};
|
||||||
static inline const Field TranscodeFormatField {"transcode-format"};
|
static inline const Field TranscodeFormatField {"transcode-format"};
|
||||||
static inline const Field TranscodeBitrateField {"transcode-bitrate"};
|
static inline const Field TranscodeBitrateField {"transcode-bitrate"};
|
||||||
|
static inline const Field ReplayGainModeField {"replaygain-mode"};
|
||||||
|
static inline const Field ReplayGainPreAmpGainField {"replaygain-preamp"};
|
||||||
static inline const Field SubsonicArtistListModeField {"subsonic-artist-list-mode"};
|
static inline const Field SubsonicArtistListModeField {"subsonic-artist-list-mode"};
|
||||||
static inline const Field SubsonicTranscodeEnableField {"subsonic-transcode-enable"};
|
static inline const Field SubsonicTranscodeEnableField {"subsonic-transcode-enable"};
|
||||||
static inline const Field SubsonicTranscodeFormatField {"subsonic-transcode-format"};
|
static inline const Field SubsonicTranscodeFormatField {"subsonic-transcode-format"};
|
||||||
@@ -60,6 +64,7 @@ class SettingsModel : public Wt::WFormModel
|
|||||||
static inline const Field PasswordConfirmField {"password-confirm"};
|
static inline const Field PasswordConfirmField {"password-confirm"};
|
||||||
|
|
||||||
using TranscodeModeModel = ValueStringModel<MediaPlayer::Settings::Transcode::Mode>;
|
using TranscodeModeModel = ValueStringModel<MediaPlayer::Settings::Transcode::Mode>;
|
||||||
|
using ReplayGainModeModel = ValueStringModel<MediaPlayer::Settings::ReplayGain::Mode>;
|
||||||
|
|
||||||
SettingsModel(bool withOldPassword)
|
SettingsModel(bool withOldPassword)
|
||||||
: _withOldPassword {withOldPassword}
|
: _withOldPassword {withOldPassword}
|
||||||
@@ -70,6 +75,8 @@ class SettingsModel : public Wt::WFormModel
|
|||||||
addField(TranscodeModeField);
|
addField(TranscodeModeField);
|
||||||
addField(TranscodeBitrateField);
|
addField(TranscodeBitrateField);
|
||||||
addField(TranscodeFormatField);
|
addField(TranscodeFormatField);
|
||||||
|
addField(ReplayGainModeField);
|
||||||
|
addField(ReplayGainPreAmpGainField);
|
||||||
addField(SubsonicTranscodeEnableField);
|
addField(SubsonicTranscodeEnableField);
|
||||||
addField(SubsonicTranscodeBitrateField);
|
addField(SubsonicTranscodeBitrateField);
|
||||||
addField(SubsonicTranscodeFormatField);
|
addField(SubsonicTranscodeFormatField);
|
||||||
@@ -83,6 +90,12 @@ class SettingsModel : public Wt::WFormModel
|
|||||||
setValidator(TranscodeModeField, createMandatoryValidator());
|
setValidator(TranscodeModeField, createMandatoryValidator());
|
||||||
setValidator(TranscodeBitrateField, createMandatoryValidator());
|
setValidator(TranscodeBitrateField, createMandatoryValidator());
|
||||||
setValidator(TranscodeFormatField, createMandatoryValidator());
|
setValidator(TranscodeFormatField, createMandatoryValidator());
|
||||||
|
setValidator(ReplayGainModeField, createMandatoryValidator());
|
||||||
|
{
|
||||||
|
auto preampGainValidator {std::make_unique<Wt::WDoubleValidator>()};
|
||||||
|
preampGainValidator->setRange(MediaPlayer::Settings::ReplayGain::minPreAmpGain, MediaPlayer::Settings::ReplayGain::maxPreAmpGain);
|
||||||
|
setValidator(ReplayGainPreAmpGainField, std::move(preampGainValidator));
|
||||||
|
}
|
||||||
setValidator(SubsonicTranscodeBitrateField, createMandatoryValidator());
|
setValidator(SubsonicTranscodeBitrateField, createMandatoryValidator());
|
||||||
setValidator(SubsonicTranscodeFormatField, createMandatoryValidator());
|
setValidator(SubsonicTranscodeFormatField, createMandatoryValidator());
|
||||||
|
|
||||||
@@ -92,6 +105,7 @@ class SettingsModel : public Wt::WFormModel
|
|||||||
std::shared_ptr<TranscodeModeModel> getTranscodeModeModel() { return _transcodeModeModel; }
|
std::shared_ptr<TranscodeModeModel> getTranscodeModeModel() { return _transcodeModeModel; }
|
||||||
std::shared_ptr<Wt::WAbstractItemModel> getTranscodeBitrateModel() { return _transcodeBitrateModel; }
|
std::shared_ptr<Wt::WAbstractItemModel> getTranscodeBitrateModel() { return _transcodeBitrateModel; }
|
||||||
std::shared_ptr<Wt::WAbstractItemModel> getTranscodeFormatModel() { return _transcodeFormatModel; }
|
std::shared_ptr<Wt::WAbstractItemModel> getTranscodeFormatModel() { return _transcodeFormatModel; }
|
||||||
|
std::shared_ptr<ReplayGainModeModel> getReplayGainModeModel() { return _replayGainModeModel; }
|
||||||
std::shared_ptr<Wt::WAbstractItemModel> getSubsonicArtistListModeModel() { return _subsonicArtistListModeModel; }
|
std::shared_ptr<Wt::WAbstractItemModel> getSubsonicArtistListModeModel() { return _subsonicArtistListModeModel; }
|
||||||
|
|
||||||
void saveData()
|
void saveData()
|
||||||
@@ -128,6 +142,12 @@ class SettingsModel : public Wt::WFormModel
|
|||||||
if (transcodeBitrateRow)
|
if (transcodeBitrateRow)
|
||||||
settings.transcode.bitrate = _transcodeBitrateModel->getValue(*transcodeBitrateRow);
|
settings.transcode.bitrate = _transcodeBitrateModel->getValue(*transcodeBitrateRow);
|
||||||
|
|
||||||
|
auto replayGainModeRow {_replayGainModeModel->getRowFromString(valueText(ReplayGainModeField))};
|
||||||
|
if (replayGainModeRow)
|
||||||
|
settings.replayGain.mode = _replayGainModeModel->getValue(*replayGainModeRow);
|
||||||
|
|
||||||
|
settings.replayGain.preAmpGain = Wt::asNumber(value(ReplayGainPreAmpGainField));
|
||||||
|
|
||||||
LmsApp->getMediaPlayer()->setSettings(settings);
|
LmsApp->getMediaPlayer()->setSettings(settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -176,6 +196,12 @@ class SettingsModel : public Wt::WFormModel
|
|||||||
auto transcodeBitrateRow {_transcodeBitrateModel->getRowFromValue(settings.transcode.bitrate)};
|
auto transcodeBitrateRow {_transcodeBitrateModel->getRowFromValue(settings.transcode.bitrate)};
|
||||||
if (transcodeBitrateRow)
|
if (transcodeBitrateRow)
|
||||||
setValue(TranscodeBitrateField, _transcodeBitrateModel->getString(*transcodeBitrateRow));
|
setValue(TranscodeBitrateField, _transcodeBitrateModel->getString(*transcodeBitrateRow));
|
||||||
|
|
||||||
|
auto replayGainModeRow {_replayGainModeModel->getRowFromValue(settings.replayGain.mode)};
|
||||||
|
if (replayGainModeRow)
|
||||||
|
setValue(ReplayGainModeField, _replayGainModeModel->getString(*replayGainModeRow));
|
||||||
|
|
||||||
|
setValue(ReplayGainPreAmpGainField, settings.replayGain.preAmpGain);
|
||||||
}
|
}
|
||||||
|
|
||||||
setValue(SubsonicTranscodeEnableField, LmsApp->getUser()->getSubsonicTranscodeEnable());
|
setValue(SubsonicTranscodeEnableField, LmsApp->getUser()->getSubsonicTranscodeEnable());
|
||||||
@@ -275,10 +301,6 @@ class SettingsModel : public Wt::WFormModel
|
|||||||
_transcodeModeModel->add(Wt::WString::tr("Lms.Settings.transcode-mode.never"), MediaPlayer::Settings::Transcode::Mode::Never);
|
_transcodeModeModel->add(Wt::WString::tr("Lms.Settings.transcode-mode.never"), MediaPlayer::Settings::Transcode::Mode::Never);
|
||||||
_transcodeModeModel->add(Wt::WString::tr("Lms.Settings.transcode-mode.if-format-not-supported"), MediaPlayer::Settings::Transcode::Mode::IfFormatNotSupported);
|
_transcodeModeModel->add(Wt::WString::tr("Lms.Settings.transcode-mode.if-format-not-supported"), MediaPlayer::Settings::Transcode::Mode::IfFormatNotSupported);
|
||||||
|
|
||||||
_subsonicArtistListModeModel = std::make_shared<ValueStringModel<User::SubsonicArtistListMode>>();
|
|
||||||
_subsonicArtistListModeModel->add(Wt::WString::tr("Lms.Settings.subsonic-artist-list-mode.all-artists"), User::SubsonicArtistListMode::AllArtists);
|
|
||||||
_subsonicArtistListModeModel->add(Wt::WString::tr("Lms.Settings.subsonic-artist-list-mode.release-artists"), User::SubsonicArtistListMode::ReleaseArtists);
|
|
||||||
|
|
||||||
_transcodeBitrateModel = std::make_shared<ValueStringModel<Bitrate>>();
|
_transcodeBitrateModel = std::make_shared<ValueStringModel<Bitrate>>();
|
||||||
for (const Bitrate bitrate : User::audioTranscodeAllowedBitrates)
|
for (const Bitrate bitrate : User::audioTranscodeAllowedBitrates)
|
||||||
{
|
{
|
||||||
@@ -291,6 +313,16 @@ class SettingsModel : public Wt::WFormModel
|
|||||||
_transcodeFormatModel->add(Wt::WString::tr("Lms.Settings.transcode-format.matroska_opus"), AudioFormat::MATROSKA_OPUS);
|
_transcodeFormatModel->add(Wt::WString::tr("Lms.Settings.transcode-format.matroska_opus"), AudioFormat::MATROSKA_OPUS);
|
||||||
_transcodeFormatModel->add(Wt::WString::tr("Lms.Settings.transcode-format.ogg_vorbis"), AudioFormat::OGG_VORBIS);
|
_transcodeFormatModel->add(Wt::WString::tr("Lms.Settings.transcode-format.ogg_vorbis"), AudioFormat::OGG_VORBIS);
|
||||||
_transcodeFormatModel->add(Wt::WString::tr("Lms.Settings.transcode-format.webm_vorbis"), AudioFormat::WEBM_VORBIS);
|
_transcodeFormatModel->add(Wt::WString::tr("Lms.Settings.transcode-format.webm_vorbis"), AudioFormat::WEBM_VORBIS);
|
||||||
|
|
||||||
|
_replayGainModeModel = std::make_shared<ReplayGainModeModel>();
|
||||||
|
_replayGainModeModel->add(Wt::WString::tr("Lms.Settings.replaygain-mode.none"), MediaPlayer::Settings::ReplayGain::Mode::None);
|
||||||
|
_replayGainModeModel->add(Wt::WString::tr("Lms.Settings.replaygain-mode.auto"), MediaPlayer::Settings::ReplayGain::Mode::Auto);
|
||||||
|
_replayGainModeModel->add(Wt::WString::tr("Lms.Settings.replaygain-mode.track"), MediaPlayer::Settings::ReplayGain::Mode::Track);
|
||||||
|
_replayGainModeModel->add(Wt::WString::tr("Lms.Settings.replaygain-mode.release"), MediaPlayer::Settings::ReplayGain::Mode::Release);
|
||||||
|
|
||||||
|
_subsonicArtistListModeModel = std::make_shared<ValueStringModel<User::SubsonicArtistListMode>>();
|
||||||
|
_subsonicArtistListModeModel->add(Wt::WString::tr("Lms.Settings.subsonic-artist-list-mode.all-artists"), User::SubsonicArtistListMode::AllArtists);
|
||||||
|
_subsonicArtistListModeModel->add(Wt::WString::tr("Lms.Settings.subsonic-artist-list-mode.release-artists"), User::SubsonicArtistListMode::ReleaseArtists);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool _withOldPassword {};
|
bool _withOldPassword {};
|
||||||
@@ -298,6 +330,7 @@ class SettingsModel : public Wt::WFormModel
|
|||||||
std::shared_ptr<TranscodeModeModel> _transcodeModeModel;
|
std::shared_ptr<TranscodeModeModel> _transcodeModeModel;
|
||||||
std::shared_ptr<ValueStringModel<Bitrate>> _transcodeBitrateModel;
|
std::shared_ptr<ValueStringModel<Bitrate>> _transcodeBitrateModel;
|
||||||
std::shared_ptr<ValueStringModel<AudioFormat>> _transcodeFormatModel;
|
std::shared_ptr<ValueStringModel<AudioFormat>> _transcodeFormatModel;
|
||||||
|
std::shared_ptr<ReplayGainModeModel> _replayGainModeModel;
|
||||||
std::shared_ptr<ValueStringModel<User::SubsonicArtistListMode>> _subsonicArtistListModeModel;
|
std::shared_ptr<ValueStringModel<User::SubsonicArtistListMode>> _subsonicArtistListModeModel;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -376,15 +409,40 @@ SettingsView::refreshView()
|
|||||||
transcodeBitrate->setModel(model->getTranscodeBitrateModel());
|
transcodeBitrate->setModel(model->getTranscodeBitrateModel());
|
||||||
t->setFormWidget(SettingsModel::TranscodeBitrateField, std::move(transcodeBitrate));
|
t->setFormWidget(SettingsModel::TranscodeBitrateField, std::move(transcodeBitrate));
|
||||||
|
|
||||||
transcodeModeRaw->sactivated().connect([=]()
|
transcodeModeRaw->activated().connect([=](int row)
|
||||||
{
|
{
|
||||||
auto row {model->getTranscodeModeModel()->getRowFromString(model->valueText(SettingsModel::TranscodeModeField))};
|
const bool enable {model->getTranscodeModeModel()->getValue(row) != MediaPlayer::Settings::Transcode::Mode::Never};
|
||||||
const bool enable = (row && (model->getTranscodeModeModel()->getValue(*row) != MediaPlayer::Settings::Transcode::Mode::Never));
|
|
||||||
model->setReadOnly(SettingsModel::TranscodeFormatField, !enable);
|
model->setReadOnly(SettingsModel::TranscodeFormatField, !enable);
|
||||||
model->setReadOnly(SettingsModel::TranscodeBitrateField, !enable);
|
model->setReadOnly(SettingsModel::TranscodeBitrateField, !enable);
|
||||||
t->updateModel(model.get());
|
t->updateModel(model.get());
|
||||||
t->updateView(model.get());
|
t->updateView(model.get());
|
||||||
});
|
});
|
||||||
|
if (LmsApp->getMediaPlayer()->getSettings()->transcode.mode == MediaPlayer::Settings::Transcode::Mode::Never)
|
||||||
|
{
|
||||||
|
model->setReadOnly(SettingsModel::TranscodeFormatField, true);
|
||||||
|
model->setReadOnly(SettingsModel::TranscodeBitrateField, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Replay gain mode
|
||||||
|
auto replayGainMode {std::make_unique<Wt::WComboBox>()};
|
||||||
|
auto* replayGainModeRaw {replayGainMode.get()};
|
||||||
|
replayGainMode->setModel(model->getReplayGainModeModel());
|
||||||
|
t->setFormWidget(SettingsModel::ReplayGainModeField, std::move(replayGainMode));
|
||||||
|
|
||||||
|
// Replay gain preampGain
|
||||||
|
auto replayGainPreampGain {std::make_unique<Wt::WDoubleSpinBox>()};
|
||||||
|
replayGainPreampGain->setRange(MediaPlayer::Settings::ReplayGain::minPreAmpGain, MediaPlayer::Settings::ReplayGain::maxPreAmpGain);
|
||||||
|
t->setFormWidget(SettingsModel::ReplayGainPreAmpGainField, std::move(replayGainPreampGain));
|
||||||
|
|
||||||
|
replayGainModeRaw->activated().connect([=](int row)
|
||||||
|
{
|
||||||
|
const bool enable {model->getReplayGainModeModel()->getValue(row) != MediaPlayer::Settings::ReplayGain::Mode::None};
|
||||||
|
model->setReadOnly(SettingsModel::SettingsModel::ReplayGainPreAmpGainField, !enable);
|
||||||
|
t->updateModel(model.get());
|
||||||
|
t->updateView(model.get());
|
||||||
|
});
|
||||||
|
if (LmsApp->getMediaPlayer()->getSettings()->replayGain.mode == MediaPlayer::Settings::ReplayGain::Mode::None)
|
||||||
|
model->setReadOnly(SettingsModel::SettingsModel::ReplayGainPreAmpGainField, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Subsonic
|
// Subsonic
|
||||||
|
|||||||
Reference in New Issue
Block a user