mirror of
https://github.com/IrosTheBeggar/mStream.git
synced 2025-10-27 07:31:02 +00:00
Add ReplayGain support.
This commit is contained in:
parent
fc3257a7fb
commit
aab63a7da2
@ -25,6 +25,7 @@ const mapFunDefault = function(left, right) {
|
||||
'album-art': left.aaFile,
|
||||
filepath: left.filepath,
|
||||
rating: right.rating,
|
||||
"replaygain-track-db": left.replaygainTrackDb,
|
||||
vpath: left.vpath
|
||||
};
|
||||
};
|
||||
@ -137,7 +138,8 @@ exports.setup = function (mstream, program) {
|
||||
"title": result[0].title ? result[0].title : null,
|
||||
"year": result[0].year ? result[0].year : null,
|
||||
"album-art": result[0].aaFile ? result[0].aaFile : null,
|
||||
"rating": result[0].rating ? result[0].rating : null
|
||||
"rating": result[0].rating ? result[0].rating : null,
|
||||
"replaygain-track-db": result[0]['replaygain-track-db'] ? result[0]['replaygain-track-db'] : null
|
||||
}
|
||||
});
|
||||
});
|
||||
@ -279,7 +281,8 @@ exports.setup = function (mstream, program) {
|
||||
"title": result[0].title ? result[0].title : null,
|
||||
"year": result[0].year ? result[0].year : null,
|
||||
"album-art": result[0].aaFile ? result[0].aaFile : null,
|
||||
"rating": result[0].rating ? result[0].rating : null
|
||||
"rating": result[0].rating ? result[0].rating : null,
|
||||
"replaygain-track-db": result[0]['replaygain-track-db'] ? result[0]['replaygain-track-db'] : null
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -448,7 +451,8 @@ exports.setup = function (mstream, program) {
|
||||
"year": row.year ? row.year : null,
|
||||
"album-art": row.aaFile ? row.aaFile : null,
|
||||
"filename": fe.basename(row.filepath),
|
||||
"rating": row.rating ? row.rating : null
|
||||
"rating": row.rating ? row.rating : null,
|
||||
"replaygain-track-db": row['replaygain-track-db'] ? row['replaygain-track-db'] : null
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -567,7 +571,8 @@ exports.setup = function (mstream, program) {
|
||||
"title": randomSong.title ? randomSong.title : null,
|
||||
"year": randomSong.year ? randomSong.year : null,
|
||||
"album-art": randomSong.aaFile ? randomSong.aaFile : null,
|
||||
"rating": randomSong.rating ? randomSong.rating : null
|
||||
"rating": randomSong.rating ? randomSong.rating : null,
|
||||
"replaygain-track-db": randomSong['replaygain-track-db'] ? randomSong['replaygain-track-db'] : null
|
||||
}
|
||||
});
|
||||
|
||||
@ -669,6 +674,7 @@ exports.setup = function (mstream, program) {
|
||||
'album-art': right.aaFile,
|
||||
filepath: right.filepath,
|
||||
rating: left.rating,
|
||||
"replaygain-track-db": right.replaygainTrackDb,
|
||||
vpath: right.vpath
|
||||
};
|
||||
};
|
||||
@ -700,7 +706,8 @@ exports.setup = function (mstream, program) {
|
||||
"year": row.year ? row.year : null,
|
||||
"album-art": row.aaFile ? row.aaFile : null,
|
||||
"filename": fe.basename(row.filepath),
|
||||
"rating": row.rating ? row.rating : null
|
||||
"rating": row.rating ? row.rating : null,
|
||||
"replaygain-track-db": row['replaygain-track-db'] ? row['replaygain-track-db'] : null
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -752,7 +759,8 @@ exports.setup = function (mstream, program) {
|
||||
"year": row.year ? row.year : null,
|
||||
"album-art": row.aaFile ? row.aaFile : null,
|
||||
"filename": fe.basename(row.filepath),
|
||||
"rating": row.rating ? row.rating : null
|
||||
"rating": row.rating ? row.rating : null,
|
||||
"replaygain-track": row.replaygainTrack ? row.replaygainTrack : null
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ -75,7 +75,8 @@ exports.insertEntries = function (arrayOfSongs, vpath) {
|
||||
"hash": song.hash,
|
||||
"aaFile": song.aaFile ? song.aaFile : null,
|
||||
"vpath": vpath,
|
||||
"ts": Math.floor(Date.now() / 1000)
|
||||
"ts": Math.floor(Date.now() / 1000),
|
||||
"replaygainTrackDb": song.replaygain_track_gain ? song.replaygain_track_gain.dB : null
|
||||
});
|
||||
|
||||
saveCounter++;
|
||||
|
||||
@ -464,3 +464,19 @@ input[type=range]:focus::-ms-fill-lower {
|
||||
input[type=range]:focus::-ms-fill-upper {
|
||||
background: #5c5c5c;
|
||||
}
|
||||
|
||||
#rg-pregain-info {
|
||||
color: rgb(102, 132, 178);
|
||||
font-weight: 800;
|
||||
font-size: 13px;
|
||||
font-family: 'Jura', sans-serif;
|
||||
width: 34px;
|
||||
padding: 13px 0;
|
||||
opacity: 0;
|
||||
transition: opacity 0.25s;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
#rg-status {
|
||||
transition: opacity 0.25s;
|
||||
}
|
||||
|
||||
@ -5,6 +5,8 @@ var MSTREAMPLAYER = (function () {
|
||||
mstreamModule.positionCache = { val: -1 };
|
||||
mstreamModule.playlist = [];
|
||||
var cacheTimeout = 30000;
|
||||
|
||||
var currentReplayGainAmp = 1.0;
|
||||
|
||||
mstreamModule.editSongMetadata = function (key, value, songIndex) {
|
||||
for (var i = 0, len = mstreamModule.playlist.length; i < len; i++) {
|
||||
@ -22,13 +24,14 @@ var MSTREAMPLAYER = (function () {
|
||||
|
||||
var localPlayerObject = getCurrentPlayer();
|
||||
var otherPlayerObject = getOtherPlayer();
|
||||
const rgainAdjustedVolume = newVolume / 100 * currentReplayGainAmp
|
||||
|
||||
if (localPlayerObject && localPlayerObject.playerObject) {
|
||||
localPlayerObject.playerObject.volume(newVolume / 100);
|
||||
localPlayerObject.playerObject.volume(rgainAdjustedVolume);
|
||||
}
|
||||
|
||||
if (otherPlayerObject && otherPlayerObject.playerObject) {
|
||||
otherPlayerObject.playerObject.volume(newVolume / 100);
|
||||
otherPlayerObject.playerObject.volume(rgainAdjustedVolume);
|
||||
}
|
||||
}
|
||||
|
||||
@ -495,6 +498,8 @@ var MSTREAMPLAYER = (function () {
|
||||
}
|
||||
|
||||
|
||||
// Should be called whenever the "metadata" field of the current song is changed, or
|
||||
// the current song is changed.
|
||||
mstreamModule.resetCurrentMetadata = function () {
|
||||
var lPlayer = getCurrentPlayer();
|
||||
var curSong = lPlayer.songObject;
|
||||
@ -505,9 +510,40 @@ var MSTREAMPLAYER = (function () {
|
||||
mstreamModule.playerStats.metadata.title = curSong.metadata.title;
|
||||
mstreamModule.playerStats.metadata.year = curSong.metadata.year;
|
||||
mstreamModule.playerStats.metadata['album-art'] = curSong.metadata['album-art'];
|
||||
mstreamModule.playerStats.metadata['replaygain-track-db'] = curSong.metadata['replaygain-track-db'];
|
||||
}
|
||||
|
||||
mstreamModule.updateReplayGainFromSong(curSong);
|
||||
}
|
||||
|
||||
// Update ReplayGain state from given song, if required.
|
||||
mstreamModule.updateReplayGainFromSong = function (song) {
|
||||
console.assert(song);
|
||||
var newRgAmpValue = undefined;
|
||||
|
||||
if (mstreamModule.playerStats.replayGain) {
|
||||
if (song.metadata) {
|
||||
const rgainDb = song.metadata['replaygain-track-db'];
|
||||
if (rgainDb) {
|
||||
// Note: the music-metadata package has a similar calculation in its Utils class, and that's used to
|
||||
// calculate a returned 'ratio' value. However, the calculation used there is actually calculating the power
|
||||
// ratio and not the amplitude ratio as required. As power is amplitude squared, that results in a volume
|
||||
// reduction that's too small (i.e. 0.25**2 = 0.00625).
|
||||
newRgAmpValue = Math.pow(10, (rgainDb + mstreamModule.playerStats.replayGainPreGainDb) / 20)
|
||||
}
|
||||
}
|
||||
|
||||
if (newRgAmpValue === undefined) {
|
||||
currentReplayGainAmp = 0.316; // -10 db for songs without ReplayGain info.
|
||||
} else {
|
||||
currentReplayGainAmp = newRgAmpValue;
|
||||
}
|
||||
} else {
|
||||
currentReplayGainAmp = 1.0;
|
||||
}
|
||||
|
||||
mstreamModule.changeVolume(mstreamModule.playerStats.volume);
|
||||
}
|
||||
|
||||
mstreamModule.resetPositionCache = function () {
|
||||
var len;
|
||||
@ -610,7 +646,9 @@ var MSTREAMPLAYER = (function () {
|
||||
"year": false,
|
||||
"album-art": false,
|
||||
"filepath": false,
|
||||
}
|
||||
},
|
||||
replayGain: false,
|
||||
replayGainPreGainDb: 0
|
||||
}
|
||||
|
||||
var playerA = {
|
||||
@ -889,6 +927,21 @@ var MSTREAMPLAYER = (function () {
|
||||
return mstreamModule.playerStats.autoDJ;
|
||||
}
|
||||
|
||||
// ReplayGain
|
||||
mstreamModule.setReplayGainActive = function (isActive) {
|
||||
mstreamModule.playerStats.replayGain = isActive;
|
||||
if (getCurrentPlayer() && getCurrentPlayer().songObject) {
|
||||
mstreamModule.updateReplayGainFromSong(getCurrentPlayer().songObject);
|
||||
}
|
||||
}
|
||||
|
||||
mstreamModule.setReplayGainPreGainDb = function (db) {
|
||||
mstreamModule.playerStats.replayGainPreGainDb = db;
|
||||
if (getCurrentPlayer() && getCurrentPlayer().songObject) {
|
||||
mstreamModule.updateReplayGainFromSong(getCurrentPlayer().songObject);
|
||||
}
|
||||
}
|
||||
|
||||
// Return an object that is assigned to Module
|
||||
return mstreamModule;
|
||||
}());
|
||||
|
||||
@ -2,6 +2,14 @@ var VUEPLAYER = (function () {
|
||||
const mstreamModule = {};
|
||||
mstreamModule.playlists = [];
|
||||
|
||||
const replayGainPreGainSettings = [
|
||||
-15.0,
|
||||
-10.0,
|
||||
-6.0,
|
||||
0.0
|
||||
];
|
||||
var replayGainInfoTimeout;
|
||||
|
||||
var currentPopperSongIndex2;
|
||||
var currentPopperSongIndex;
|
||||
var currentPopperSong;
|
||||
@ -218,6 +226,10 @@ var VUEPLAYER = (function () {
|
||||
created: function () {
|
||||
if (typeof(Storage) !== "undefined") {
|
||||
this.curVol = localStorage.getItem("volume");
|
||||
MSTREAMPLAYER.setReplayGainActive(localStorage.getItem("replayGain") == "true");
|
||||
|
||||
const rgPregain = Number(localStorage.getItem("replayGainPreGainDb"));
|
||||
MSTREAMPLAYER.setReplayGainPreGainDb(rgPregain === NaN ? 0 : rgPregain);
|
||||
}
|
||||
MSTREAMPLAYER.changeVolume(parseInt(this.curVol));
|
||||
},
|
||||
@ -296,6 +308,43 @@ var VUEPLAYER = (function () {
|
||||
toggleAutoDJ: function () {
|
||||
MSTREAMPLAYER.toggleAutoDJ();
|
||||
},
|
||||
toggleReplayGain: function () {
|
||||
// With a series of clicks, allow the user to first activate ReplayGain, then progress through a list of
|
||||
// settings for the desired level of pre-gain, and then finally disable ReplayGain again.
|
||||
if (replayGainInfoTimeout) { clearTimeout(replayGainInfoTimeout); }
|
||||
|
||||
var pregainInfoElement = document.getElementById('rg-pregain-info')
|
||||
var rgStatusElement = document.getElementById('rg-status')
|
||||
|
||||
if (!this.playerStats.replayGain) {
|
||||
MSTREAMPLAYER.setReplayGainPreGainDb(replayGainPreGainSettings[0]);
|
||||
MSTREAMPLAYER.setReplayGainActive(true);
|
||||
} else {
|
||||
const settingsIdx = replayGainPreGainSettings.indexOf(this.playerStats.replayGainPreGainDb);
|
||||
if (settingsIdx == -1 || settingsIdx >= replayGainPreGainSettings.length - 1) {
|
||||
MSTREAMPLAYER.setReplayGainActive(false);
|
||||
pregainInfoElement.style.opacity = "0.0";
|
||||
rgStatusElement.style.opacity = "1.0";
|
||||
} else {
|
||||
MSTREAMPLAYER.setReplayGainPreGainDb(replayGainPreGainSettings[settingsIdx + 1]);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.playerStats.replayGain) {
|
||||
pregainInfoElement.style.opacity = "1.0";
|
||||
rgStatusElement.style.opacity = "0.0";
|
||||
|
||||
replayGainInfoTimeout = setTimeout(function () {
|
||||
pregainInfoElement.style.opacity = "0.0";
|
||||
rgStatusElement.style.opacity = "1.0";
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
if (typeof(Storage) !== "undefined") {
|
||||
localStorage.setItem("replayGain", this.playerStats.replayGain);
|
||||
localStorage.setItem("replayGainPreGainDb", this.playerStats.replayGainPreGainDb);
|
||||
}
|
||||
},
|
||||
fadeOverlay: function () {
|
||||
if ($('#main-overlay').is(':visible')) {
|
||||
$('#main-overlay').fadeOut("slow");
|
||||
|
||||
@ -425,6 +425,7 @@
|
||||
<p v-cloak class="metadata-panel-text">Artist: {{ (meta.artist) ? meta.artist : '' }}</p>
|
||||
<p v-cloak class="metadata-panel-text">Album: {{ (meta.album) ? meta.album : '' }}</p>
|
||||
<p v-cloak class="metadata-panel-text">Year: {{ (meta.year) ? meta.year : '' }}</p>
|
||||
<p v-cloak class="metadata-panel-text">Gain: {{ (meta['replaygain-track-db']) ? String(meta['replaygain-track-db']) + " db" : 'n/a' }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -474,6 +475,10 @@
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div v-on:click="toggleReplayGain" class="next-button" title="ReplayGain">
|
||||
<div id="rg-pregain-info">{{playerStats.replayGainPreGainDb}}db</div>
|
||||
<svg id="rg-status" v-bind:class="{ 'aux-button-active': playerStats.replayGain }" class="center" xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMidYMid" style="width:35px;webkit-logical-width:35px;webkit-logical-height:25px;user-select:none;transform-origin:12.5px 12.5px;r:0;perspective-origin:12.5px 12.5px;overflow-y:hidden;overflow-x:hidden;inline-size:35px;height:25px;d:none;block-size:25px;background:0% 0%/auto padding-box border-box" overflow="hidden" display="block" fill="#fff"><g transform="translate(-.938 19.85)" style="y:0;user-select:none;transform:matrix(1,0,0,1,-.9375,19.85);perspective-origin:0 0"><g class="ld" style="y:0;x:0;user-select:none;transform-origin:7.9375px 0;transform:none;r:0;perspective-origin:0 0;line-height:31.4286px;font:400 22px/31.4286px 'Varela Round','century gothic',verdana;d:none"><text style="y:0;user-select:none;r:0;perspective-origin:7.9375px 0;line-height:31.4286px;font:400 22px/31.4286px Arial" white-space="nowrap" display="block">R</text></g></g><g transform="translate(14.938 19.85)" style="y:0;user-select:none;transform:matrix(1,0,0,1,14.9375,19.85);perspective-origin:0 0"><g class="ld" style="y:0;x:0;user-select:none;transform-origin:5.5px 0;transform:none;r:0;perspective-origin:0 0;line-height:31.4286px;font:400 22px/31.4286px 'Varela Round','century gothic',verdana;d:none"><text style="y:0;user-select:none;r:0;perspective-origin:5.5px 0;line-height:31.4286px;font:400 22px/31.4286px Arial" white-space="nowrap" display="block">G</text></g></g></svg>
|
||||
</div>
|
||||
<div v-on:click="toggleVolume" class="player-button">
|
||||
<img class="noselect fill-white center" :src="volumeSrc" title="Mute/Unmute">
|
||||
</div>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user