first pass audio mixer automatic muting of noisy streams, tour guide improvements, new lightExample.js, hair hangs over cone 'body'

This commit is contained in:
Philip Rosedale 2014-11-05 16:58:58 -08:00
parent a6c8fb7449
commit 688bd0f34f
12 changed files with 121 additions and 26 deletions

View file

@ -61,8 +61,7 @@
const float LOUDNESS_TO_DISTANCE_RATIO = 0.00001f;
const float DEFAULT_ATTENUATION_PER_DOUBLING_IN_DISTANCE = 0.18;
const float DEFAULT_NOISE_MUTING_THRESHOLD = 100.0f;
const float DEFAULT_NOISE_MUTING_THRESHOLD = 0.003f;
const QString AUDIO_MIXER_LOGGING_TARGET_NAME = "audio-mixer";
const QString AUDIO_ENV_GROUP_KEY = "audio_env";
const QString AUDIO_BUFFER_GROUP_KEY = "audio_buffer";
@ -81,7 +80,6 @@ bool AudioMixer::_enableFilter = true;
bool AudioMixer::shouldMute(float quietestFrame, float loudestFrame) {
return (quietestFrame > _noiseMutingThreshold);
qDebug() << "Muting, quiestest frame = " << quietestFrame;
}
AudioMixer::AudioMixer(const QByteArray& packet) :
@ -1015,7 +1013,17 @@ void AudioMixer::parseSettingsObject(const QJsonObject &settingsObject) {
qDebug() << "Attenuation per doubling in distance changed to" << _attenuationPerDoublingInDistance;
}
}
const QString NOISE_MUTING_THRESHOLD = "noise_muting_threshold";
if (audioEnvGroupObject[NOISE_MUTING_THRESHOLD].isString()) {
bool ok = false;
float noiseMutingThreshold = audioEnvGroupObject[NOISE_MUTING_THRESHOLD].toString().toFloat(&ok);
if (ok) {
_noiseMutingThreshold = noiseMutingThreshold;
qDebug() << "Noise muting threshold changed to" << _noiseMutingThreshold;
}
}
const QString FILTER_KEY = "enable_filter";
if (audioEnvGroupObject[FILTER_KEY].isBool()) {
_enableFilter = audioEnvGroupObject[FILTER_KEY].toBool();

View file

@ -89,6 +89,14 @@
"default": "0.18",
"advanced": false
},
{
"name": "noise_muting_threshold",
"label": "Noise Muting Threshold",
"help": "Loudness value for noise background between 0 and 1.0 (0: mute everyone, 1.0: never mute)",
"placeholder": "0.003",
"default": "0.003",
"advanced": false
},
{
"name": "enable_filter",
"type": "checkbox",

View file

@ -12,6 +12,8 @@ var MIN_CHANGE = 2.0;
var LANDING_DISTANCE = 2.0;
var LANDING_RANDOM = 0.2;
var relativePosition;
function update(deltaTime) {
if (Math.random() < deltaTime) {
@ -26,20 +28,15 @@ function update(deltaTime) {
}
if (guide) {
relativePosition = Vec3.subtract(MyAvatar.position, lastGuidePosition);
// Check whether guide has moved, update if so
if (Vec3.length(lastGuidePosition) == 0.0) {
lastGuidePosition = guide.position;
} else {
if (Vec3.length(Vec3.subtract(lastGuidePosition, guide.position)) > MIN_CHANGE) {
var meToGuide = Vec3.multiply(Vec3.normalize(Vec3.subtract(guide.position, MyAvatar.position)), LANDING_DISTANCE);
var newPosition = Vec3.subtract(guide.position, meToGuide);
newPosition = Vec3.sum(newPosition, { x: Math.random() * LANDING_RANDOM - LANDING_RANDOM / 2.0,
y: 0,
z: Math.random() * LANDING_RANDOM - LANDING_RANDOM / 2.0 });
var newPosition = Vec3.sum(guide.position, relativePosition);
MyAvatar.position = newPosition;
lastGuidePosition = guide.position;
MyAvatar.orientation = guide.orientation;
}
}
}

46
examples/lightExample.js Normal file
View file

@ -0,0 +1,46 @@
//
// spotlightExample.js
// examples
//
// Created by Brad Hefta-Gaub on 10/28/14.
// Copyright 2014 High Fidelity, Inc.
//
// This is an example script that demonstrates creating and editing a particle
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
var position = Vec3.sum(MyAvatar.position, Quat.getFront(Camera.getOrientation()));
var sphereID = Entities.addEntity({
type: "Sphere",
position: position,
dimensions: { x: 0.1, y: 0.1, z: 0.1 },
color: { red: 255, green: 255, blue: 0 }
});
var lightID = Entities.addEntity({
type: "Light",
position: position,
dimensions: { x: 1, y: 1, z: 1 },
angularVelocity: { x: 0, y: 0, z: 0 },
angularDamping: 0,
isSpotlight: false,
diffuseColor: { red: 255, green: 255, blue: 0 },
ambientColor: { red: 0, green: 0, blue: 0 },
specularColor: { red: 255, green: 255, blue: 255 },
constantAttenuation: 0,
linearAttenuation: 1,
quadraticAttenuation: 0,
exponent: 0,
cutoff: 180, // in degrees
});
Script.scriptEnding.connect(function() {
print("Deleted sphere and light");
Entities.deleteEntity(sphereID);
Entities.deleteEntity(lightID);
});

View file

@ -728,9 +728,8 @@ void Audio::handleAudioInput() {
_loudestFrame = _lastInputLoudness;
}
const int FRAMES_FOR_NOISE_DETECTION = 300;
const int FRAMES_FOR_NOISE_DETECTION = 400;
if (_inputFrameCounter++ > FRAMES_FOR_NOISE_DETECTION) {
qDebug() << "Quietest/loudest frame: " << _quietestFrame << " / " << _loudestFrame << " NGfloor: " << _noiseGateMeasuredFloor;
_quietestFrame = std::numeric_limits<float>::max();
_loudestFrame = 0.0f;
_inputFrameCounter = 0;

View file

@ -52,12 +52,10 @@ Hair::Hair(int strands,
glm::vec3 thisVertex;
for (int strand = 0; strand < _strands; strand++) {
float strandAngle = randFloat() * PI;
float azimuth;
float elevation = - (randFloat() * PI);
azimuth = PI_OVER_TWO;
if (randFloat() < 0.5f) {
azimuth *= -1.0f;
}
float azimuth = (float)strand / (float)_strands * PI * 2.0f;
float elevation = 0.0f;
glm::vec3 thisStrand(sinf(azimuth) * cosf(elevation), sinf(elevation), -cosf(azimuth) * cosf(elevation));
thisStrand *= _radius;
@ -115,11 +113,22 @@ void Hair::simulate(float deltaTime) {
glm::vec3 diff = thisPosition - _hairLastPosition[vertexIndex];
_hairPosition[vertexIndex] += diff * HAIR_DAMPING;
/*
// Resolve collisions with sphere
if (glm::length(_hairPosition[vertexIndex]) < _radius) {
_hairPosition[vertexIndex] += glm::normalize(_hairPosition[vertexIndex]) *
(_radius - glm::length(_hairPosition[vertexIndex]));
} */
// Collide with a conical body descending from the root of the hair
glm::vec3 thisVertex = _hairPosition[vertexIndex];
float depth = -thisVertex.y;
thisVertex.y = 0.0f;
const float BODY_CONE_ANGLE = 0.30;
if (glm::length(thisVertex) < depth * BODY_CONE_ANGLE) {
_hairPosition[vertexIndex] += glm::normalize(thisVertex) * (depth * BODY_CONE_ANGLE - glm::length(thisVertex));
}
// Add random thing driven by loudness
float loudnessFactor = (_loudness > SOUND_THRESHOLD) ? logf(_loudness - SOUND_THRESHOLD) / 2000.0f : 0.0f;

View file

@ -1,4 +1,4 @@
//
//
// EntityTreeRenderer.cpp
// interface/src
//

View file

@ -26,7 +26,8 @@ AudioInjector::AudioInjector(QObject* parent) :
_sound(NULL),
_options(),
_shouldStop(false),
_currentSendPosition(0)
_currentSendPosition(0),
_loudness(0.0f)
{
}
@ -34,7 +35,8 @@ AudioInjector::AudioInjector(Sound* sound, const AudioInjectorOptions& injectorO
_sound(sound),
_options(injectorOptions),
_shouldStop(false),
_currentSendPosition(0)
_currentSendPosition(0),
_loudness(0.0f)
{
}
@ -42,6 +44,10 @@ void AudioInjector::setOptions(AudioInjectorOptions& options) {
_options = options;
}
float AudioInjector::getLoudness() {
return _loudness;
}
const uchar MAX_INJECTOR_VOLUME = 0xFF;
void AudioInjector::injectAudio() {
@ -113,6 +119,15 @@ void AudioInjector::injectAudio() {
int bytesToCopy = std::min(((_options.isStereo()) ? 2 : 1) * NETWORK_BUFFER_LENGTH_BYTES_PER_CHANNEL,
soundByteArray.size() - _currentSendPosition);
// Measure the loudness of this frame
_loudness = 0.0f;
for (int i = 0; i < bytesToCopy; i += sizeof(int16_t)) {
_loudness += abs(*reinterpret_cast<int16_t*>(soundByteArray.data() + _currentSendPosition + i)) /
(MAX_SAMPLE_VALUE / 2.0f);
}
_loudness /= (float)(bytesToCopy / sizeof(int16_t));
memcpy(injectAudioPacket.data() + positionOptionOffset,
&_options.getPosition(),
sizeof(_options.getPosition()));

View file

@ -33,6 +33,8 @@ public slots:
void stop() { _shouldStop = true; }
void setOptions(AudioInjectorOptions& options);
void setCurrentSendPosition(int currentSendPosition) { _currentSendPosition = currentSendPosition; }
float getLoudness();
signals:
void finished();
private:
@ -40,6 +42,7 @@ private:
AudioInjectorOptions _options;
bool _shouldStop;
int _currentSendPosition;
float _loudness;
};
Q_DECLARE_METATYPE(AudioInjector*)

View file

@ -45,7 +45,15 @@ bool AudioScriptingInterface::isInjectorPlaying(AudioInjector* injector) {
return (injector != NULL);
}
void AudioScriptingInterface::startDrumSound(float volume, float frequency, float duration, float decay,
float AudioScriptingInterface::getLoudness(AudioInjector* injector) {
if (injector) {
return injector->getLoudness();
} else {
return 0.0f;
}
}
void AudioScriptingInterface::startDrumSound(float volume, float frequency, float duration, float decay,
const AudioInjectorOptions* injectorOptions) {
Sound* sound = new Sound(volume, frequency, duration, decay);

View file

@ -23,6 +23,7 @@ public slots:
static AudioInjector* playSound(Sound* sound, const AudioInjectorOptions* injectorOptions = NULL);
static void stopInjector(AudioInjector* injector);
static bool isInjectorPlaying(AudioInjector* injector);
static float getLoudness(AudioInjector* injector);
static void startDrumSound(float volume, float frequency, float duration, float decay,
const AudioInjectorOptions* injectorOptions = NULL);

View file

@ -45,8 +45,9 @@ void PositionalAudioStream::resetStats() {
void PositionalAudioStream::updateLastPopOutputLoudnessAndTrailingLoudness() {
_lastPopOutputLoudness = _ringBuffer.getFrameLoudness(_lastPopOutput);
const int TRAILING_AVERAGE_FRAMES = 100;
const float CURRENT_FRAME_RATIO = 1.0f / TRAILING_AVERAGE_FRAMES;
const int TRAILING_MUTE_THRESHOLD_FRAMES = 400;
const int TRAILING_LOUDNESS_FRAMES = 200;
const float CURRENT_FRAME_RATIO = 1.0f / TRAILING_LOUDNESS_FRAMES;
const float PREVIOUS_FRAMES_RATIO = 1.0f - CURRENT_FRAME_RATIO;
const float LOUDNESS_EPSILON = 0.000001f;
@ -59,7 +60,7 @@ void PositionalAudioStream::updateLastPopOutputLoudnessAndTrailingLoudness() {
_lastPopOutputTrailingLoudness = 0;
}
}
if (_frameCounter++ == TRAILING_AVERAGE_FRAMES) {
if (_frameCounter++ == TRAILING_MUTE_THRESHOLD_FRAMES) {
_frameCounter = 0;
_quietestTrailingFrameLoudness = std::numeric_limits<float>::max();
_loudestTrailingFrameLoudness = 0.0f;