diff --git a/interface/resources/images/Audio-Loudness-Icons/vol-0.svg b/interface/resources/images/Audio-Loudness-Icons/vol-0.svg new file mode 100755 index 0000000000..72f247c238 --- /dev/null +++ b/interface/resources/images/Audio-Loudness-Icons/vol-0.svg @@ -0,0 +1,12 @@ + + + + + diff --git a/interface/resources/images/Audio-Loudness-Icons/vol-1.svg b/interface/resources/images/Audio-Loudness-Icons/vol-1.svg new file mode 100755 index 0000000000..9570b9ae6c --- /dev/null +++ b/interface/resources/images/Audio-Loudness-Icons/vol-1.svg @@ -0,0 +1,13 @@ + + + + + + diff --git a/interface/resources/images/Audio-Loudness-Icons/vol-2.svg b/interface/resources/images/Audio-Loudness-Icons/vol-2.svg new file mode 100755 index 0000000000..a2175be39e --- /dev/null +++ b/interface/resources/images/Audio-Loudness-Icons/vol-2.svg @@ -0,0 +1,16 @@ + + + + + + + diff --git a/interface/resources/images/Audio-Loudness-Icons/vol-3.svg b/interface/resources/images/Audio-Loudness-Icons/vol-3.svg new file mode 100755 index 0000000000..21b1095941 --- /dev/null +++ b/interface/resources/images/Audio-Loudness-Icons/vol-3.svg @@ -0,0 +1,19 @@ + + + + + + + + diff --git a/interface/resources/images/Audio-Loudness-Icons/vol-4.svg b/interface/resources/images/Audio-Loudness-Icons/vol-4.svg new file mode 100755 index 0000000000..de0b4027eb --- /dev/null +++ b/interface/resources/images/Audio-Loudness-Icons/vol-4.svg @@ -0,0 +1,21 @@ + + + + + + + + + diff --git a/interface/resources/qml/hifi/Pal.qml b/interface/resources/qml/hifi/Pal.qml index e0f2df76ce..4735ae9312 100644 --- a/interface/resources/qml/hifi/Pal.qml +++ b/interface/resources/qml/hifi/Pal.qml @@ -13,6 +13,7 @@ import QtQuick 2.5 import QtQuick.Controls 1.4 +import QtGraphicalEffects 1.0 import "../styles-uit" import "../controls-uit" as HifiControls @@ -163,6 +164,14 @@ Rectangle { onSortIndicatorColumnChanged: sortModel() onSortIndicatorOrderChanged: sortModel() + TableViewColumn { + role: "avgAudioLevel" + title: "VOL" + width: actionButtonWidth + movable: false + resizable: false + } + TableViewColumn { id: displayNameHeader role: "displayName" @@ -185,13 +194,6 @@ Rectangle { movable: false resizable: false } - TableViewColumn { - role: "avgAudioLevel" - title: "VOL" - width: actionButtonWidth - movable: false - resizable: false - } TableViewColumn { visible: iAmAdmin role: "mute" @@ -226,7 +228,8 @@ Rectangle { id: itemCell property bool isCheckBox: styleData.role === "personalMute" || styleData.role === "ignore" property bool isButton: styleData.role === "mute" || styleData.role === "kick" - property bool isText: styleData.role == "avgAudioLevel" + property bool isAvgAudio: styleData.role === "avgAudioLevel" + // This NameCard refers to the cell that contains an avatar's // DisplayName and UserName NameCard { @@ -236,7 +239,7 @@ Rectangle { userName: model ? model.userName : "" audioLevel: model ? model.audioLevel : 0.0 avgAudioLevel: model ? model.avgAudioLevel : 0.0 - visible: !isCheckBox && !isButton && !isText + visible: !isCheckBox && !isButton && !isAvgAudio uuid: model ? model.sessionId : "" selected: styleData.selected isAdmin: model && model.admin @@ -246,14 +249,19 @@ Rectangle { // Anchors anchors.left: parent.left } - Text { + Image { + visible: isAvgAudio + function getImage() { + var fileName = "../../../images/Audio-Loudness-Icons/vol-"; + fileName += (4.0*(model ? model.avgAudioLevel : 0.0)).toFixed(0); + fileName += ".svg"; + return fileName; + } id: avgAudioVolume - text: model ? (10 * model.avgAudioLevel).toFixed(0) : 0.0 - visible: isText - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - width: parent.width - height: parent.height + width: hifi.dimensions.tableHeaderHeight + fillMode: Image.PreserveAspectFit + source: getImage() + anchors.verticalCenter: parent.verticalCenter } // This CheckBox belongs in the columns that contain the stateful action buttons ("Mute" & "Ignore" for now) diff --git a/scripts/system/pal.js b/scripts/system/pal.js index e9f5ba0a67..fe4eea48a4 100644 --- a/scripts/system/pal.js +++ b/scripts/system/pal.js @@ -197,6 +197,17 @@ HighlightedEntity.updateOverlays = function updateHighlightedEntities() { }); }; +/* this contains current gain for a given node (by session id). More efficient than + * querying it, plus there isn't a getGain function so why write one */ +var sessionGains = {}; +function convertDbToLinear(decibels) { + // +20db = 10x, 0dB = 1x, -10dB = 0.1x, etc... + // but, your perception is that something 2x as loud is +10db + // so we go from -60 to +20 or 1/64x to 4x. For now, we can + // maybe scale the signal this way?? + return Math.pow(2, decibels/10.0); +} + function fromQml(message) { // messages are {method, params}, like json-rpc. See also sendToQml. var data; switch (message.method) { @@ -242,6 +253,8 @@ function fromQml(message) { // messages are {method, params}, like json-rpc. See UserActivityLogger.palAction("avatar_gain_changed", data['sessionId']); } else { Users.setAvatarGain(data['sessionId'], data['gain']); + sessionGains[data['sessionId']] = convertDbToLinear(data['gain']); + print("set " + data['sessionId'] + " to " + sessionGains[data['sessionId']]); } break; case 'displayNameUpdate': @@ -576,6 +589,7 @@ function scaleAudio(val) { } return audioLevel; } + function getAudioLevel(id) { // the VU meter should work similarly to the one in AvatarInputs: log scale, exponentially averaged // But of course it gets the data at a different rate, so we tweak the averaging ratio and frequency @@ -594,9 +608,10 @@ function getAudioLevel(id) { // natural log, so to get log base 2, just divide by ln(2). audioLevel = scaleAudio(Math.log(data.accumulatedLevel + 1) / LOG2); avgAudioLevel = scaleAudio(Math.log(data.longAccumulatedLevel + 1) / LOG2); - + // scale avgAudioLevel given that there can be a gain (4x to 1/64x) + avgAudioLevel = Math.min(1.0, avgAudioLevel *(sessionGains[id] || 0.75)); + data.avgAudioLevel = avgAudioLevel; data.audioLevel = audioLevel; - data.averageAudioLevel = avgAudioLevel; } return [audioLevel, avgAudioLevel]; }