Merge branch 'master' of https://github.com/highfidelity/hifi into PAL_v2

This commit is contained in:
howard-stearns 2017-03-15 15:45:36 -07:00
commit 155e1b8e85
9 changed files with 106 additions and 96 deletions

View file

@ -17,6 +17,7 @@ module.exports = {
"Clipboard": false, "Clipboard": false,
"Controller": false, "Controller": false,
"DialogsManager": false, "DialogsManager": false,
"DebugDraw": false,
"Entities": false, "Entities": false,
"FaceTracker": false, "FaceTracker": false,
"GlobalServices": false, "GlobalServices": false,

View file

@ -608,6 +608,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
} }
} }
// make sure the debug draw singleton is initialized on the main thread.
DebugDraw::getInstance().removeMarker("");
_runningMarker.startRunningMarker(); _runningMarker.startRunningMarker();

View file

@ -1028,7 +1028,7 @@ void AudioClient::handleAudioInput() {
// if we performed the noise gate we can get values from it instead of enumerating the samples again // if we performed the noise gate we can get values from it instead of enumerating the samples again
_lastInputLoudness = _inputGate.getLastLoudness(); _lastInputLoudness = _inputGate.getLastLoudness();
if (_inputGate.clippedInLastFrame()) { if (_inputGate.clippedInLastBlock()) {
_timeSinceLastClip = 0.0f; _timeSinceLastClip = 0.0f;
} }
@ -1049,10 +1049,9 @@ void AudioClient::handleAudioInput() {
emit inputReceived({ reinterpret_cast<char*>(networkAudioSamples), numNetworkBytes }); emit inputReceived({ reinterpret_cast<char*>(networkAudioSamples), numNetworkBytes });
if (_inputGate.openedInLastFrame()) { if (_inputGate.openedInLastBlock()) {
emit noiseGateOpened(); emit noiseGateOpened();
} } else if (_inputGate.closedInLastBlock()) {
if (_inputGate.closedInLastFrame()) {
emit noiseGateClosed(); emit noiseGateClosed();
} }
@ -1072,7 +1071,7 @@ void AudioClient::handleAudioInput() {
// the output from the input gate (eventually, this could be crossfaded) // the output from the input gate (eventually, this could be crossfaded)
// and allow the codec to properly encode down to silent/zero. If we still // and allow the codec to properly encode down to silent/zero. If we still
// have _lastInputLoudness of 0 in our NEXT frame, we will send a silent packet // have _lastInputLoudness of 0 in our NEXT frame, we will send a silent packet
if (_lastInputLoudness == 0 && !_inputGate.closedInLastFrame()) { if (_lastInputLoudness == 0 && !_inputGate.closedInLastBlock()) {
packetType = PacketType::SilentAudioFrame; packetType = PacketType::SilentAudioFrame;
_silentOutbound.increment(); _silentOutbound.increment();
} else { } else {

View file

@ -45,13 +45,13 @@
#include <AudioReverb.h> #include <AudioReverb.h>
#include <AudioLimiter.h> #include <AudioLimiter.h>
#include <AudioConstants.h> #include <AudioConstants.h>
#include <AudioNoiseGate.h>
#include <shared/RateCounter.h> #include <shared/RateCounter.h>
#include <plugins/CodecPlugin.h> #include <plugins/CodecPlugin.h>
#include "AudioIOStats.h" #include "AudioIOStats.h"
#include "AudioNoiseGate.h"
#ifdef _WIN32 #ifdef _WIN32
#pragma warning( push ) #pragma warning( push )

View file

@ -1,6 +1,6 @@
// //
// AudioNoiseGate.cpp // AudioNoiseGate.cpp
// interface/src/audio // libraries/audio
// //
// Created by Stephen Birarda on 2014-12-16. // Created by Stephen Birarda on 2014-12-16.
// Copyright 2014 High Fidelity, Inc. // Copyright 2014 High Fidelity, Inc.
@ -9,35 +9,29 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
// //
#include "AudioNoiseGate.h"
#include <cstdlib> #include <cstdlib>
#include <string.h> #include <string.h>
#include <AudioConstants.h> #include "AudioConstants.h"
#include "AudioNoiseGate.h"
const float AudioNoiseGate::CLIPPING_THRESHOLD = 0.90f; const float AudioNoiseGate::CLIPPING_THRESHOLD = 0.90f;
AudioNoiseGate::AudioNoiseGate() : AudioNoiseGate::AudioNoiseGate() :
_inputFrameCounter(0),
_lastLoudness(0.0f), _lastLoudness(0.0f),
_quietestFrame(std::numeric_limits<float>::max()), _didClipInLastBlock(false),
_loudestFrame(0.0f),
_didClipInLastFrame(false),
_dcOffset(0.0f), _dcOffset(0.0f),
_measuredFloor(0.0f), _measuredFloor(0.0f),
_sampleCounter(0), _sampleCounter(0),
_isOpen(false), _isOpen(false),
_framesToClose(0) _blocksToClose(0) {}
{
}
void AudioNoiseGate::removeDCOffset(int16_t* samples, int numSamples) { void AudioNoiseGate::removeDCOffset(int16_t* samples, int numSamples) {
// //
// DC Offset correction // DC Offset correction
// //
// Measure the DC offset over a trailing number of frames, and remove it from the input signal. // Measure the DC offset over a trailing number of blocks, and remove it from the input signal.
// This causes the noise background measurements and server muting to be more accurate. Many off-board // This causes the noise background measurements and server muting to be more accurate. Many off-board
// ADC's have a noticeable DC offset. // ADC's have a noticeable DC offset.
// //
@ -51,7 +45,7 @@ void AudioNoiseGate::removeDCOffset(int16_t* samples, int numSamples) {
// Update measured DC offset // Update measured DC offset
measuredDcOffset /= numSamples; measuredDcOffset /= numSamples;
if (_dcOffset == 0.0f) { if (_dcOffset == 0.0f) {
// On first frame, copy over measured offset // On first block, copy over measured offset
_dcOffset = measuredDcOffset; _dcOffset = measuredDcOffset;
} else { } else {
_dcOffset = DC_OFFSET_AVERAGING * _dcOffset + (1.0f - DC_OFFSET_AVERAGING) * measuredDcOffset; _dcOffset = DC_OFFSET_AVERAGING * _dcOffset + (1.0f - DC_OFFSET_AVERAGING) * measuredDcOffset;
@ -69,96 +63,85 @@ void AudioNoiseGate::gateSamples(int16_t* samples, int numSamples) {
// //
// NOISE_GATE_HEIGHT: How loud you have to speak relative to noise background to open the gate. // NOISE_GATE_HEIGHT: How loud you have to speak relative to noise background to open the gate.
// Make this value lower for more sensitivity and less rejection of noise. // Make this value lower for more sensitivity and less rejection of noise.
// NOISE_GATE_WIDTH: The number of samples in an audio frame for which the height must be exceeded // NOISE_GATE_WIDTH: The number of samples in an audio block for which the height must be exceeded
// to open the gate. // to open the gate.
// NOISE_GATE_CLOSE_FRAME_DELAY: Once the noise is below the gate height for the frame, how many frames // NOISE_GATE_CLOSE_BLOCK_DELAY: Once the noise is below the gate height for the block, how many blocks
// will we wait before closing the gate. // will we wait before closing the gate.
// NOISE_GATE_FRAMES_TO_AVERAGE: How many audio frames should we average together to compute noise floor. // NOISE_GATE_BLOCKS_TO_AVERAGE: How many audio blocks should we average together to compute noise floor.
// More means better rejection but also can reject continuous things like singing. // More means better rejection but also can reject continuous things like singing.
// NUMBER_OF_NOISE_SAMPLE_FRAMES: How often should we re-evaluate the noise floor? // NUMBER_OF_NOISE_SAMPLE_BLOCKS: How often should we re-evaluate the noise floor?
float loudness = 0; float loudness = 0;
int thisSample = 0; int thisSample = 0;
int samplesOverNoiseGate = 0; int samplesOverNoiseGate = 0;
const float NOISE_GATE_HEIGHT = 7.0f; const float NOISE_GATE_HEIGHT = 7.0f;
const int NOISE_GATE_WIDTH = 5; const int NOISE_GATE_WIDTH = 5;
const int NOISE_GATE_CLOSE_FRAME_DELAY = 5; const int NOISE_GATE_CLOSE_BLOCK_DELAY = 5;
const int NOISE_GATE_FRAMES_TO_AVERAGE = 5; const int NOISE_GATE_BLOCKS_TO_AVERAGE = 5;
// Check clipping, and check if should open noise gate // Check clipping, and check if should open noise gate
_didClipInLastFrame = false; _didClipInLastBlock = false;
for (int i = 0; i < numSamples; i++) { for (int i = 0; i < numSamples; i++) {
thisSample = std::abs(samples[i]); thisSample = std::abs(samples[i]);
if (thisSample >= ((float) AudioConstants::MAX_SAMPLE_VALUE * CLIPPING_THRESHOLD)) { if (thisSample >= ((float) AudioConstants::MAX_SAMPLE_VALUE * CLIPPING_THRESHOLD)) {
_didClipInLastFrame = true; _didClipInLastBlock = true;
} }
loudness += thisSample; loudness += thisSample;
// Noise Reduction: Count peaks above the average loudness // Noise Reduction: Count peaks above the average loudness
if (thisSample > (_measuredFloor * NOISE_GATE_HEIGHT)) { if (thisSample > (_measuredFloor * NOISE_GATE_HEIGHT)) {
samplesOverNoiseGate++; samplesOverNoiseGate++;
} }
} }
_lastLoudness = fabs(loudness / numSamples); _lastLoudness = fabs(loudness / numSamples);
if (_quietestFrame > _lastLoudness) {
_quietestFrame = _lastLoudness;
}
if (_loudestFrame < _lastLoudness) {
_loudestFrame = _lastLoudness;
}
const int FRAMES_FOR_NOISE_DETECTION = 400;
if (_inputFrameCounter++ > FRAMES_FOR_NOISE_DETECTION) {
_quietestFrame = std::numeric_limits<float>::max();
_loudestFrame = 0.0f;
_inputFrameCounter = 0;
}
// If Noise Gate is enabled, check and turn the gate on and off // If Noise Gate is enabled, check and turn the gate on and off
float averageOfAllSampleFrames = 0.0f; float averageOfAllSampleBlocks = 0.0f;
_sampleFrames[_sampleCounter++] = _lastLoudness; _sampleBlocks[_sampleCounter++] = _lastLoudness;
if (_sampleCounter == NUMBER_OF_NOISE_SAMPLE_FRAMES) { if (_sampleCounter == NUMBER_OF_NOISE_SAMPLE_BLOCKS) {
float smallestSample = std::numeric_limits<float>::max(); float smallestSample = std::numeric_limits<float>::max();
for (int i = 0; i <= NUMBER_OF_NOISE_SAMPLE_FRAMES - NOISE_GATE_FRAMES_TO_AVERAGE; i += NOISE_GATE_FRAMES_TO_AVERAGE) { for (int i = 0; i <= NUMBER_OF_NOISE_SAMPLE_BLOCKS - NOISE_GATE_BLOCKS_TO_AVERAGE; i += NOISE_GATE_BLOCKS_TO_AVERAGE) {
float thisAverage = 0.0f; float thisAverage = 0.0f;
for (int j = i; j < i + NOISE_GATE_FRAMES_TO_AVERAGE; j++) { for (int j = i; j < i + NOISE_GATE_BLOCKS_TO_AVERAGE; j++) {
thisAverage += _sampleFrames[j]; thisAverage += _sampleBlocks[j];
averageOfAllSampleFrames += _sampleFrames[j]; averageOfAllSampleBlocks += _sampleBlocks[j];
} }
thisAverage /= NOISE_GATE_FRAMES_TO_AVERAGE; thisAverage /= NOISE_GATE_BLOCKS_TO_AVERAGE;
if (thisAverage < smallestSample) { if (thisAverage < smallestSample) {
smallestSample = thisAverage; smallestSample = thisAverage;
} }
} }
averageOfAllSampleFrames /= NUMBER_OF_NOISE_SAMPLE_FRAMES; averageOfAllSampleBlocks /= NUMBER_OF_NOISE_SAMPLE_BLOCKS;
_measuredFloor = smallestSample; _measuredFloor = smallestSample;
_sampleCounter = 0; _sampleCounter = 0;
} }
_closedInLastFrame = false; _closedInLastBlock = false;
_openedInLastFrame = false; _openedInLastBlock = false;
if (samplesOverNoiseGate > NOISE_GATE_WIDTH) { if (samplesOverNoiseGate > NOISE_GATE_WIDTH) {
_openedInLastFrame = !_isOpen; _openedInLastBlock = !_isOpen;
_isOpen = true; _isOpen = true;
_framesToClose = NOISE_GATE_CLOSE_FRAME_DELAY; _blocksToClose = NOISE_GATE_CLOSE_BLOCK_DELAY;
} else { } else {
if (--_framesToClose == 0) { if (--_blocksToClose == 0) {
_closedInLastFrame = _isOpen; _closedInLastBlock = _isOpen;
_isOpen = false; _isOpen = false;
} }
} }
if (!_isOpen) { if (!_isOpen) {
if (_closedInLastFrame) { // First block after being closed gets faded to silence, we fade across
// would be nice to do a little crossfade to silence // the entire block on fading out. All subsequent blocks are muted by being slammed
// to zeros
if (_closedInLastBlock) {
float fadeSlope = (1.0f / numSamples);
for (int i = 0; i < numSamples; i++) { for (int i = 0; i < numSamples; i++) {
float fadedSample = (1.0f - (float)i / (float)numSamples) * (float)samples[i]; float fadedSample = (1.0f - ((float)i * fadeSlope)) * (float)samples[i];
samples[i] = (int16_t)fadedSample; samples[i] = (int16_t)fadedSample;
} }
} else { } else {
@ -167,10 +150,14 @@ void AudioNoiseGate::gateSamples(int16_t* samples, int numSamples) {
_lastLoudness = 0; _lastLoudness = 0;
} }
if (_openedInLastFrame) { if (_openedInLastBlock) {
// would be nice to do a little crossfade from silence // would be nice to do a little crossfade from silence, but we only want to fade
for (int i = 0; i < numSamples; i++) { // across the first 1/10th of the block, because we don't want to miss early
float fadedSample = ((float)i / (float)numSamples) * (float)samples[i]; // transients.
int fadeSamples = numSamples / 10; // fade over 1/10th of the samples
float fadeSlope = (1.0f / fadeSamples);
for (int i = 0; i < fadeSamples; i++) {
float fadedSample = (float)i * fadeSlope * (float)samples[i];
samples[i] = (int16_t)fadedSample; samples[i] = (int16_t)fadedSample;
} }
} }

View file

@ -1,6 +1,6 @@
// //
// AudioNoiseGate.h // AudioNoiseGate.h
// interface/src/audio // libraries/audio
// //
// Created by Stephen Birarda on 2014-12-16. // Created by Stephen Birarda on 2014-12-16.
// Copyright 2014 High Fidelity, Inc. // Copyright 2014 High Fidelity, Inc.
@ -14,38 +14,35 @@
#include <stdint.h> #include <stdint.h>
const int NUMBER_OF_NOISE_SAMPLE_FRAMES = 300; const int NUMBER_OF_NOISE_SAMPLE_BLOCKS = 300;
class AudioNoiseGate { class AudioNoiseGate {
public: public:
AudioNoiseGate(); AudioNoiseGate();
void gateSamples(int16_t* samples, int numSamples); void gateSamples(int16_t* samples, int numSamples);
void removeDCOffset(int16_t* samples, int numSamples); void removeDCOffset(int16_t* samples, int numSamples);
bool clippedInLastFrame() const { return _didClipInLastFrame; } bool clippedInLastBlock() const { return _didClipInLastBlock; }
bool closedInLastFrame() const { return _closedInLastFrame; } bool closedInLastBlock() const { return _closedInLastBlock; }
bool openedInLastFrame() const { return _openedInLastFrame; } bool openedInLastBlock() const { return _openedInLastBlock; }
bool isOpen() const { return _isOpen; } bool isOpen() const { return _isOpen; }
float getMeasuredFloor() const { return _measuredFloor; } float getMeasuredFloor() const { return _measuredFloor; }
float getLastLoudness() const { return _lastLoudness; } float getLastLoudness() const { return _lastLoudness; }
static const float CLIPPING_THRESHOLD; static const float CLIPPING_THRESHOLD;
private: private:
int _inputFrameCounter;
float _lastLoudness; float _lastLoudness;
float _quietestFrame; bool _didClipInLastBlock;
float _loudestFrame;
bool _didClipInLastFrame;
float _dcOffset; float _dcOffset;
float _measuredFloor; float _measuredFloor;
float _sampleFrames[NUMBER_OF_NOISE_SAMPLE_FRAMES]; float _sampleBlocks[NUMBER_OF_NOISE_SAMPLE_BLOCKS];
int _sampleCounter; int _sampleCounter;
bool _isOpen; bool _isOpen;
bool _closedInLastFrame { false }; bool _closedInLastBlock { false };
bool _openedInLastFrame { false }; bool _openedInLastBlock { false };
int _framesToClose; int _blocksToClose;
}; };
#endif // hifi_AudioNoiseGate_h #endif // hifi_AudioNoiseGate_h

View file

@ -143,12 +143,35 @@ void PhysicsEngine::addObjectToDynamicsWorld(ObjectMotionState* motionState) {
} }
void PhysicsEngine::removeObjects(const VectorOfMotionStates& objects) { void PhysicsEngine::removeObjects(const VectorOfMotionStates& objects) {
// first bump and prune contacts for all objects in the list // bump and prune contacts for all objects in the list
for (auto object : objects) { for (auto object : objects) {
bumpAndPruneContacts(object); bumpAndPruneContacts(object);
} }
// then remove them if (_activeStaticBodies.size() > 0) {
// _activeStaticBodies was not cleared last frame.
// The only way to get here is if a static object were moved but we did not actually step the simulation last
// frame (because the framerate is faster than our physics simulation rate). When this happens we must scan
// _activeStaticBodies for objects that were recently deleted so we don't try to access a dangling pointer.
for (auto object : objects) {
btRigidBody* body = object->getRigidBody();
std::vector<btRigidBody*>::reverse_iterator itr = _activeStaticBodies.rbegin();
while (itr != _activeStaticBodies.rend()) {
if (body == *itr) {
if (*itr != *(_activeStaticBodies.rbegin())) {
// swap with rbegin
*itr = *(_activeStaticBodies.rbegin());
}
_activeStaticBodies.pop_back();
break;
}
++itr;
}
}
}
// remove bodies
for (auto object : objects) { for (auto object : objects) {
btRigidBody* body = object->getRigidBody(); btRigidBody* body = object->getRigidBody();
if (body) { if (body) {

View file

@ -346,7 +346,9 @@ void AnimDebugDraw::update() {
numVerts += (int)markerMap.size() * VERTICES_PER_BONE; numVerts += (int)markerMap.size() * VERTICES_PER_BONE;
auto myAvatarMarkerMap = DebugDraw::getInstance().getMyAvatarMarkerMap(); auto myAvatarMarkerMap = DebugDraw::getInstance().getMyAvatarMarkerMap();
numVerts += (int)myAvatarMarkerMap.size() * VERTICES_PER_BONE; numVerts += (int)myAvatarMarkerMap.size() * VERTICES_PER_BONE;
numVerts += (int)DebugDraw::getInstance().getRays().size() * VERTICES_PER_RAY; auto rays = DebugDraw::getInstance().getRays();
DebugDraw::getInstance().clearRays();
numVerts += (int)rays.size() * VERTICES_PER_RAY;
// allocate verts! // allocate verts!
std::vector<AnimDebugDrawData::Vertex> vertices; std::vector<AnimDebugDrawData::Vertex> vertices;
@ -398,10 +400,9 @@ void AnimDebugDraw::update() {
} }
// draw rays from shared DebugDraw singleton // draw rays from shared DebugDraw singleton
for (auto& iter : DebugDraw::getInstance().getRays()) { for (auto& iter : rays) {
addLine(std::get<0>(iter), std::get<1>(iter), std::get<2>(iter), v); addLine(std::get<0>(iter), std::get<1>(iter), std::get<2>(iter), v);
} }
DebugDraw::getInstance().clearRays();
data._vertexBuffer->resize(sizeof(AnimDebugDrawData::Vertex) * numVerts); data._vertexBuffer->resize(sizeof(AnimDebugDrawData::Vertex) * numVerts);
data._vertexBuffer->setSubData<AnimDebugDrawData::Vertex>(0, vertices); data._vertexBuffer->setSubData<AnimDebugDrawData::Vertex>(0, vertices);

View file

@ -142,7 +142,7 @@ QString encodeEntityIdIntoEntityUrl(const QString& url, const QString& entityID)
QString ScriptEngine::logException(const QScriptValue& exception) { QString ScriptEngine::logException(const QScriptValue& exception) {
auto message = formatException(exception); auto message = formatException(exception);
scriptErrorMessage(qPrintable(message)); scriptErrorMessage(message);
return message; return message;
} }
@ -453,7 +453,7 @@ void ScriptEngine::loadURL(const QUrl& scriptURL, bool reload) {
} }
void ScriptEngine::scriptErrorMessage(const QString& message) { void ScriptEngine::scriptErrorMessage(const QString& message) {
qCCritical(scriptengine) << message; qCCritical(scriptengine) << qPrintable(message);
emit errorMessage(message); emit errorMessage(message);
} }