Merge pull request #9261 from davidkelly/dk/workingVUMetersInPal

Working VU meters in PAL
This commit is contained in:
David Kelly 2016-12-23 13:24:38 -08:00 committed by GitHub
commit 68fb81902b
3 changed files with 69 additions and 4 deletions

View file

@ -33,6 +33,7 @@ Row {
property string userName: ""
property int displayTextHeight: 18
property int usernameTextHeight: 12
property real audioLevel: 0.0
Column {
id: avatarImage
@ -91,7 +92,6 @@ Row {
// VU Meter
Rectangle { // CHANGEME to the appropriate type!
id: nameCardVUMeter
objectName: "AvatarInputs"
// Size
width: parent.width
height: 8
@ -110,7 +110,7 @@ Row {
Rectangle {
id: vuMeterLevel
// Size
width: (nameCardVUMeter.audioLevel) * parent.width
width: (thisNameCard.audioLevel) * parent.width
// Style
color: "#dbdbdb" // Very appropriate hex value here
radius: parent.radius

View file

@ -58,6 +58,7 @@ Item {
// Properties
displayName: myData.displayName
userName: myData.userName
audioLevel: myData.audioLevel
// Size
width: nameCardWidth
height: parent.height
@ -190,6 +191,7 @@ Item {
// Properties
displayName: styleData.value
userName: model.userName
audioLevel: model.audioLevel
visible: !isCheckBox
// Size
width: nameCardWidth
@ -292,7 +294,7 @@ Item {
}
property var userData: []
property var myData: ({displayName: "", userName: ""}) // valid dummy until set
property var myData: ({displayName: "", userName: "", audioLevel: 0.0}) // valid dummy until set
property bool iAmAdmin: false
function findSessionIndex(sessionId, optionalData) { // no findIndex in .qml
var i, data = optionalData || userData, length = data.length;
@ -343,6 +345,21 @@ Item {
userData[userIndex].userName = userName; // Defensive programming
}
break;
case 'updateAudioLevel':
for (var userId in message.params) {
var audioLevel = message.params[userId];
// If the userId is 0, we're updating "myData".
if (userId == 0) {
myData.audioLevel = audioLevel;
myCard.audioLevel = audioLevel; // Defensive programming
} else {
console.log("userid:" + userId);
var userIndex = findSessionIndex(userId);
userModel.get(userIndex).audioLevel = audioLevel;
userData[userIndex].audioLevel = audioLevel; // Defensive programming
}
}
break;
default:
console.log('Unrecognized message:', JSON.stringify(message));
}

View file

@ -119,7 +119,8 @@ function populateUserList() {
var avatarPalDatum = {
displayName: avatar.sessionDisplayName,
userName: '',
sessionId: id || ''
sessionId: id || '',
audioLevel: 0.0
};
// If the current user is an admin OR
// they're requesting their own username ("id" is blank)...
@ -262,6 +263,53 @@ function onClicked() {
pal.setVisible(!pal.visible);
}
var AVERAGING_RATIO = 0.05
var LOUDNESS_FLOOR = 11.0;
var LOUDNESS_SCALE = 2.8 / 5.0;
var LOG2 = Math.log(2.0);
var AUDIO_LEVEL_UPDATE_INTERVAL_MS = 100; // 10hz for now (change this and change the AVERAGING_RATIO too)
var accumulatedLevels = {};
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
// of updating (the latter for efficiency too).
var avatar = AvatarList.getAvatar(id);
var audioLevel = 0.0;
// we will do exponential moving average by taking some the last loudness and averaging
accumulatedLevels[id] = AVERAGING_RATIO * (accumulatedLevels[id] || 0 ) + (1 - AVERAGING_RATIO) * (avatar.audioLoudness);
// add 1 to insure we don't go log() and hit -infinity. Math.log is
// natural log, so to get log base 2, just divide by ln(2).
var logLevel = Math.log(accumulatedLevels[id] + 1) / LOG2;
if (logLevel <= LOUDNESS_FLOOR) {
audioLevel = logLevel / LOUDNESS_FLOOR * LOUDNESS_SCALE;
} else {
audioLevel = (logLevel - (LOUDNESS_FLOOR - 1.0)) * LOUDNESS_SCALE;
}
if (audioLevel > 1.0) {
audioLevel = 1;
}
return audioLevel;
}
// we will update the audioLevels periodically
// TODO: tune for efficiency - expecially with large numbers of avatars
Script.setInterval(function () {
if (pal.visible) {
var param = {};
AvatarList.getAvatarIdentifiers().sort().forEach(function (id) {
var level = getAudioLevel(id);
// qml didn't like an object with null/empty string for a key, so...
var userId = id || 0;
param[userId]= level;
});
pal.sendToQml({method: 'updateAudioLevel', params: param});
}
}, AUDIO_LEVEL_UPDATE_INTERVAL_MS);
//
// Button state.
//