mirror of
https://github.com/overte-org/overte.git
synced 2025-04-20 01:43:53 +02:00
Working first pass
Seems roughly same as mic meter. Works for other avatars, though using agent avatars (crowd-agent.js + summon.js), seems not to work. I'll investigate that...
This commit is contained in:
parent
e67d6e347d
commit
2e897e0cc9
3 changed files with 62 additions and 4 deletions
|
@ -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
|
||||
|
|
|
@ -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,18 @@ Item {
|
|||
userData[userIndex].userName = userName; // Defensive programming
|
||||
}
|
||||
break;
|
||||
case 'updateAudioLevel':
|
||||
var userId = message.params[0];
|
||||
var audioLevel = message.params[1];
|
||||
if (!userId) {
|
||||
myData.audioLevel = audioLevel;
|
||||
myCard.audioLevel = audioLevel;
|
||||
} else {
|
||||
var userIndex = findSessionIndex(userId);
|
||||
userModel.get(userIndex).audioLevel = audioLevel;
|
||||
userData[userIndex].audioLevel = audioLevel;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
console.log('Unrecognized message:', JSON.stringify(message));
|
||||
}
|
||||
|
|
|
@ -119,7 +119,8 @@ function populateUserList() {
|
|||
var avatarPalDatum = {
|
||||
displayName: avatar.sessionDisplayName,
|
||||
userName: '',
|
||||
sessionId: id || ''
|
||||
sessionId: id || '',
|
||||
audioLevel: getAudioLevel(id)
|
||||
};
|
||||
// If the current user is an admin OR
|
||||
// they're requesting their own username ("id" is blank)...
|
||||
|
@ -262,6 +263,49 @@ 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) {
|
||||
AvatarList.getAvatarIdentifiers().sort().forEach(function (id) {
|
||||
var level = getAudioLevel(id);
|
||||
pal.sendToQml({method: 'updateAudioLevel', params: [id, level]});
|
||||
});
|
||||
}
|
||||
}, AUDIO_LEVEL_UPDATE_INTERVAL_MS);
|
||||
//
|
||||
// Button state.
|
||||
//
|
||||
|
|
Loading…
Reference in a new issue