From e076b32f9c29160a744d29e167428f52446e52e8 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 6 Mar 2017 10:15:53 -0800 Subject: [PATCH 01/18] don't automatically unhook overlays from hands unless they were grabbable overlays --- scripts/system/controllers/handControllerGrab.js | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/scripts/system/controllers/handControllerGrab.js b/scripts/system/controllers/handControllerGrab.js index d982a032cc..cd18d6f932 100644 --- a/scripts/system/controllers/handControllerGrab.js +++ b/scripts/system/controllers/handControllerGrab.js @@ -3213,13 +3213,21 @@ function MyController(hand) { } _this.previouslyUnhooked[childID] = now; - // we don't know if it's an entity or an overlay + if (Overlays.getProperty(childID, "grabbable")) { + // only auto-unhook overlays that were flagged as grabbable. this avoids unhooking overlays + // used in tutorial. + Overlays.editOverlay(childID, { + parentID: previousParentID, + parentJointIndex: previousParentJointIndex + }); + } Entities.editEntity(childID, { parentID: previousParentID, parentJointIndex: previousParentJointIndex }); - Overlays.editOverlay(childID, { parentID: previousParentID, parentJointIndex: previousParentJointIndex }); } else { Entities.editEntity(childID, { parentID: NULL_UUID }); - Overlays.editOverlay(childID, { parentID: NULL_UUID }); + if (Overlays.getProperty(childID, "grabbable")) { + Overlays.editOverlay(childID, { parentID: NULL_UUID }); + } } } }); From 74323cb1f0065e3e41c97b8c615cdb12de50f370 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 6 Mar 2017 11:45:49 -0800 Subject: [PATCH 02/18] remove debug print --- scripts/system/controllers/handControllerGrab.js | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/system/controllers/handControllerGrab.js b/scripts/system/controllers/handControllerGrab.js index cd18d6f932..5b99738a78 100644 --- a/scripts/system/controllers/handControllerGrab.js +++ b/scripts/system/controllers/handControllerGrab.js @@ -3195,7 +3195,6 @@ function MyController(hand) { // we appear to be holding something and this script isn't in a state that would be holding something. // unhook it. if we previously took note of this entity's parent, put it back where it was. This // works around some problems that happen when more than one hand or avatar is passing something around. - print("disconnecting stray child of hand: (" + _this.hand + ") " + childID); if (_this.previousParentID[childID]) { var previousParentID = _this.previousParentID[childID]; var previousParentJointIndex = _this.previousParentJointIndex[childID]; From c52c43e23d27142118fae920b37970f61f67cfc1 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 6 Mar 2017 19:35:00 -0800 Subject: [PATCH 03/18] Remove weighted offset, special case downward pressure --- .../animation/src/AnimInverseKinematics.cpp | 48 +++++++------------ 1 file changed, 17 insertions(+), 31 deletions(-) diff --git a/libraries/animation/src/AnimInverseKinematics.cpp b/libraries/animation/src/AnimInverseKinematics.cpp index 173af3fdf6..fa8e4654f6 100644 --- a/libraries/animation/src/AnimInverseKinematics.cpp +++ b/libraries/animation/src/AnimInverseKinematics.cpp @@ -488,13 +488,7 @@ const AnimPoseVec& AnimInverseKinematics::overlay(const AnimVariantMap& animVars // measure new _hipsOffset for next frame // by looking for discrepancies between where a targeted endEffector is // and where it wants to be (after IK solutions are done) - - // use weighted average between HMD and other targets - float HMD_WEIGHT = 10.0f; - float OTHER_WEIGHT = 1.0f; - float totalWeight = 0.0f; - - glm::vec3 additionalHipsOffset = Vectors::ZERO; + glm::vec3 newHipsOffset = Vectors::ZERO; for (auto& target: targets) { int targetIndex = target.getIndex(); if (targetIndex == _headIndex && _headIndex != -1) { @@ -505,42 +499,34 @@ const AnimPoseVec& AnimInverseKinematics::overlay(const AnimVariantMap& animVars glm::vec3 under = _skeleton->getAbsolutePose(_headIndex, underPoses).trans(); glm::vec3 actual = _skeleton->getAbsolutePose(_headIndex, _relativePoses).trans(); const float HEAD_OFFSET_SLAVE_FACTOR = 0.65f; - additionalHipsOffset += (OTHER_WEIGHT * HEAD_OFFSET_SLAVE_FACTOR) * (under- actual); - totalWeight += OTHER_WEIGHT; + newHipsOffset += HEAD_OFFSET_SLAVE_FACTOR * (actual - under); } else if (target.getType() == IKTarget::Type::HmdHead) { + // we want to shift the hips to bring the head to its designated position glm::vec3 actual = _skeleton->getAbsolutePose(_headIndex, _relativePoses).trans(); - glm::vec3 thisOffset = target.getTranslation() - actual; - glm::vec3 futureHipsOffset = _hipsOffset + thisOffset; - if (glm::length(glm::vec2(futureHipsOffset.x, futureHipsOffset.z)) < _maxHipsOffsetLength) { - // it is imperative to shift the hips and bring the head to its designated position - // so we slam newHipsOffset here and ignore all other targets - additionalHipsOffset = futureHipsOffset - _hipsOffset; - totalWeight = 0.0f; - break; - } else { - additionalHipsOffset += HMD_WEIGHT * (target.getTranslation() - actual); - totalWeight += HMD_WEIGHT; - } + _hipsOffset += target.getTranslation() - actual; + // and ignore all other targets + newHipsOffset = _hipsOffset; + break; + } else if (target.getType() == IKTarget::Type::RotationAndPosition) { + glm::vec3 actualPosition = _skeleton->getAbsolutePose(targetIndex, _relativePoses).trans(); + glm::vec3 targetPosition = target.getTranslation(); + newHipsOffset += targetPosition - actualPosition; + + // Add downward pressure on the hips + newHipsOffset *= 0.95f; + newHipsOffset -= 1.0f; } } else if (target.getType() == IKTarget::Type::RotationAndPosition) { glm::vec3 actualPosition = _skeleton->getAbsolutePose(targetIndex, _relativePoses).trans(); glm::vec3 targetPosition = target.getTranslation(); - additionalHipsOffset += OTHER_WEIGHT * (targetPosition - actualPosition); - totalWeight += OTHER_WEIGHT; + newHipsOffset += targetPosition - actualPosition; } } - if (totalWeight > 1.0f) { - additionalHipsOffset /= totalWeight; - } - - // Add downward pressure on the hips - additionalHipsOffset *= 0.95f; - additionalHipsOffset -= 1.0f; // smooth transitions by relaxing _hipsOffset toward the new value const float HIPS_OFFSET_SLAVE_TIMESCALE = 0.10f; float tau = dt < HIPS_OFFSET_SLAVE_TIMESCALE ? dt / HIPS_OFFSET_SLAVE_TIMESCALE : 1.0f; - _hipsOffset += additionalHipsOffset * tau; + _hipsOffset += (newHipsOffset - _hipsOffset) * tau; // clamp the hips offset float hipsOffsetLength = glm::length(_hipsOffset); From 8ae6f2727d4e0faef0af43bb6b853fdd3dac17c5 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Tue, 7 Mar 2017 17:52:55 -0800 Subject: [PATCH 04/18] add support for double click messages to overlays and entities --- interface/src/Application.cpp | 18 +++++++- interface/src/Application.h | 2 +- interface/src/ui/overlays/Overlays.cpp | 20 ++++++++ interface/src/ui/overlays/Overlays.h | 3 ++ .../src/EntityTreeRenderer.cpp | 46 +++++++++++++++++++ .../src/EntityTreeRenderer.h | 3 ++ libraries/shared/src/PointerEvent.cpp | 5 ++ libraries/shared/src/PointerEvent.h | 7 +-- 8 files changed, 99 insertions(+), 5 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index f870bd9f83..671c530b27 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3174,7 +3174,23 @@ void Application::mousePressEvent(QMouseEvent* event) { } } -void Application::mouseDoublePressEvent(QMouseEvent* event) const { +void Application::mouseDoublePressEvent(QMouseEvent* event) { + auto offscreenUi = DependencyManager::get(); + auto eventPosition = getApplicationCompositor().getMouseEventPosition(event); + QPointF transformedPos = offscreenUi->mapToVirtualScreen(eventPosition, _glWidget); + QMouseEvent mappedEvent(event->type(), + transformedPos, + event->screenPos(), event->button(), + event->buttons(), event->modifiers()); + + if (!_aboutToQuit) { + getOverlays().mouseDoublePressEvent(&mappedEvent); + if (!_controllerScriptingInterface->areEntityClicksCaptured()) { + getEntities()->mouseDoublePressEvent(&mappedEvent); + } + } + + // if one of our scripts have asked to capture this event, then stop processing it if (_controllerScriptingInterface->isMouseCaptured()) { return; diff --git a/interface/src/Application.h b/interface/src/Application.h index c4ba760153..98080783a6 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -494,7 +494,7 @@ private: void mouseMoveEvent(QMouseEvent* event); void mousePressEvent(QMouseEvent* event); - void mouseDoublePressEvent(QMouseEvent* event) const; + void mouseDoublePressEvent(QMouseEvent* event); void mouseReleaseEvent(QMouseEvent* event); void touchBeginEvent(QTouchEvent* event); diff --git a/interface/src/ui/overlays/Overlays.cpp b/interface/src/ui/overlays/Overlays.cpp index ad7fbd6cc2..f40dd522c4 100644 --- a/interface/src/ui/overlays/Overlays.cpp +++ b/interface/src/ui/overlays/Overlays.cpp @@ -769,6 +769,26 @@ bool Overlays::mousePressEvent(QMouseEvent* event) { return false; } +bool Overlays::mouseDoublePressEvent(QMouseEvent* event) { + PerformanceTimer perfTimer("Overlays::mouseDoublePressEvent"); + + PickRay ray = qApp->computePickRay(event->x(), event->y()); + RayToOverlayIntersectionResult rayPickResult = findRayIntersectionForMouseEvent(ray); + if (rayPickResult.intersects) { + _currentClickingOnOverlayID = rayPickResult.overlayID; + + // Only Web overlays can have focus. + auto thisOverlay = std::dynamic_pointer_cast(getOverlay(_currentClickingOnOverlayID)); + if (thisOverlay) { + auto pointerEvent = calculatePointerEvent(thisOverlay, ray, rayPickResult, event, PointerEvent::Press); + emit mouseDoublePressOnOverlay(_currentClickingOnOverlayID, pointerEvent); + return true; + } + } + emit mouseDoublePressOffOverlay(); + return false; +} + bool Overlays::mouseReleaseEvent(QMouseEvent* event) { PerformanceTimer perfTimer("Overlays::mouseReleaseEvent"); diff --git a/interface/src/ui/overlays/Overlays.h b/interface/src/ui/overlays/Overlays.h index 5c22e46880..c35c7c1ced 100644 --- a/interface/src/ui/overlays/Overlays.h +++ b/interface/src/ui/overlays/Overlays.h @@ -101,6 +101,7 @@ public: OverlayID addOverlay(Overlay::Pointer overlay); bool mousePressEvent(QMouseEvent* event); + bool mouseDoublePressEvent(QMouseEvent* event); bool mouseReleaseEvent(QMouseEvent* event); bool mouseMoveEvent(QMouseEvent* event); @@ -300,9 +301,11 @@ signals: void panelDeleted(OverlayID id); void mousePressOnOverlay(OverlayID overlayID, const PointerEvent& event); + void mouseDoublePressOnOverlay(OverlayID overlayID, const PointerEvent& event); void mouseReleaseOnOverlay(OverlayID overlayID, const PointerEvent& event); void mouseMoveOnOverlay(OverlayID overlayID, const PointerEvent& event); void mousePressOffOverlay(); + void mouseDoublePressOffOverlay(); void hoverEnterOverlay(OverlayID overlayID, const PointerEvent& event); void hoverOverOverlay(OverlayID overlayID, const PointerEvent& event); diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index bd25bcf905..27e00b47c6 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -735,6 +735,52 @@ void EntityTreeRenderer::mousePressEvent(QMouseEvent* event) { } } +void EntityTreeRenderer::mouseDoublePressEvent(QMouseEvent* event) { + // If we don't have a tree, or we're in the process of shutting down, then don't + // process these events. + if (!_tree || _shuttingDown) { + return; + } + PerformanceTimer perfTimer("EntityTreeRenderer::mouseDoublePressEvent"); + PickRay ray = _viewState->computePickRay(event->x(), event->y()); + + bool precisionPicking = !_dontDoPrecisionPicking; + RayToEntityIntersectionResult rayPickResult = findRayIntersectionWorker(ray, Octree::Lock, precisionPicking); + if (rayPickResult.intersects) { + //qCDebug(entitiesrenderer) << "mouseDoublePressEvent over entity:" << rayPickResult.entityID; + + QString urlString = rayPickResult.properties.getHref(); + QUrl url = QUrl(urlString, QUrl::StrictMode); + if (url.isValid() && !url.isEmpty()){ + DependencyManager::get()->handleLookupString(urlString); + } + + glm::vec2 pos2D = projectOntoEntityXYPlane(rayPickResult.entity, ray, rayPickResult); + PointerEvent pointerEvent(PointerEvent::Press, MOUSE_POINTER_ID, + pos2D, rayPickResult.intersection, + rayPickResult.surfaceNormal, ray.direction, + toPointerButton(*event), toPointerButtons(*event)); + + emit mouseDoublePressOnEntity(rayPickResult.entityID, pointerEvent); + + if (_entitiesScriptEngine) { + _entitiesScriptEngine->callEntityScriptMethod(rayPickResult.entityID, "mouseDoublePressOnEntity", pointerEvent); + } + + _currentClickingOnEntityID = rayPickResult.entityID; + emit clickDownOnEntity(_currentClickingOnEntityID, pointerEvent); + if (_entitiesScriptEngine) { + _entitiesScriptEngine->callEntityScriptMethod(_currentClickingOnEntityID, "doubleclickOnEntity", pointerEvent); + } + + _lastPointerEvent = pointerEvent; + _lastPointerEventValid = true; + + } else { + emit mouseDoublePressOffEntity(); + } +} + void EntityTreeRenderer::mouseReleaseEvent(QMouseEvent* event) { // If we don't have a tree, or we're in the process of shutting down, then don't // process these events. diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.h b/libraries/entities-renderer/src/EntityTreeRenderer.h index c11738c459..753f25310c 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.h +++ b/libraries/entities-renderer/src/EntityTreeRenderer.h @@ -90,6 +90,7 @@ public: // event handles which may generate entity related events void mouseReleaseEvent(QMouseEvent* event); void mousePressEvent(QMouseEvent* event); + void mouseDoublePressEvent(QMouseEvent* event); void mouseMoveEvent(QMouseEvent* event); /// connect our signals to anEntityScriptingInterface for firing of events related clicking, @@ -103,9 +104,11 @@ public: signals: void mousePressOnEntity(const EntityItemID& entityItemID, const PointerEvent& event); + void mouseDoublePressOnEntity(const EntityItemID& entityItemID, const PointerEvent& event); void mouseMoveOnEntity(const EntityItemID& entityItemID, const PointerEvent& event); void mouseReleaseOnEntity(const EntityItemID& entityItemID, const PointerEvent& event); void mousePressOffEntity(); + void mouseDoublePressOffEntity(); void clickDownOnEntity(const EntityItemID& entityItemID, const PointerEvent& event); void holdingClickOnEntity(const EntityItemID& entityItemID, const PointerEvent& event); diff --git a/libraries/shared/src/PointerEvent.cpp b/libraries/shared/src/PointerEvent.cpp index ed9acb9ada..e429204e94 100644 --- a/libraries/shared/src/PointerEvent.cpp +++ b/libraries/shared/src/PointerEvent.cpp @@ -47,6 +47,9 @@ QScriptValue PointerEvent::toScriptValue(QScriptEngine* engine, const PointerEve case Press: obj.setProperty("type", "Press"); break; + case DoublePress: + obj.setProperty("type", "DoublePress"); + break; case Release: obj.setProperty("type", "Release"); break; @@ -128,6 +131,8 @@ void PointerEvent::fromScriptValue(const QScriptValue& object, PointerEvent& eve QString typeStr = type.isString() ? type.toString() : "Move"; if (typeStr == "Press") { event._type = Press; + } else if (typeStr == "DoublePress") { + event._type = DoublePress; } else if (typeStr == "Release") { event._type = Release; } else { diff --git a/libraries/shared/src/PointerEvent.h b/libraries/shared/src/PointerEvent.h index 054835c4fc..166c4be592 100644 --- a/libraries/shared/src/PointerEvent.h +++ b/libraries/shared/src/PointerEvent.h @@ -26,9 +26,10 @@ public: }; enum EventType { - Press, // A button has just been pressed - Release, // A button has just been released - Move // The pointer has just moved + Press, // A button has just been pressed + DoublePress, // A button has just been double pressed + Release, // A button has just been released + Move // The pointer has just moved }; PointerEvent(); From d7c3677b2211bd3b906bbf40c1d23b61f827b2d5 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Tue, 7 Mar 2017 17:55:03 -0800 Subject: [PATCH 05/18] add example --- .../entityScripts/doubleClickExample.js | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 script-archive/entityScripts/doubleClickExample.js diff --git a/script-archive/entityScripts/doubleClickExample.js b/script-archive/entityScripts/doubleClickExample.js new file mode 100644 index 0000000000..daff2668ed --- /dev/null +++ b/script-archive/entityScripts/doubleClickExample.js @@ -0,0 +1,19 @@ +(function() { + var _this; + function DoubleClickExample() { + _this = this; + return; + } + + DoubleClickExample.prototype = { + clickDownOnEntity: function() { + print("clickDownOnEntity"); + }, + + doubleclickOnEntity: function() { + print("doubleclickOnEntity"); + } + + }; + return new DoubleClickExample(); +}); \ No newline at end of file From 7acfcf6750704b8b76523cf23d64f2291477df6a Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Wed, 8 Mar 2017 18:15:32 -0800 Subject: [PATCH 06/18] fade in and out when opening/closing the noise gate --- libraries/audio-client/src/AudioNoiseGate.cpp | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/libraries/audio-client/src/AudioNoiseGate.cpp b/libraries/audio-client/src/AudioNoiseGate.cpp index ac45f98f0b..0ced518097 100644 --- a/libraries/audio-client/src/AudioNoiseGate.cpp +++ b/libraries/audio-client/src/AudioNoiseGate.cpp @@ -142,7 +142,11 @@ void AudioNoiseGate::gateSamples(int16_t* samples, int numSamples) { _sampleCounter = 0; } + + bool isOpeningGate = false; + if (samplesOverNoiseGate > NOISE_GATE_WIDTH) { + isOpeningGate = !_isOpen; _isOpen = true; _framesToClose = NOISE_GATE_CLOSE_FRAME_DELAY; } else { @@ -154,7 +158,23 @@ void AudioNoiseGate::gateSamples(int16_t* samples, int numSamples) { } } if (!_isOpen) { - memset(samples, 0, numSamples * sizeof(int16_t)); + if (_closedInLastFrame) { + // would be nice to do a little crossfade from silence + for (int i = 0; i < numSamples; i++) { + float fadedSample = (1.0f - (float)i / (float)numSamples) * (float)samples[i]; + samples[i] = (int16_t)fadedSample; + } + } else { + memset(samples, 0, numSamples * sizeof(int16_t)); + } _lastLoudness = 0; } + + if (isOpeningGate) { + // would be nice to do a little crossfade from silence + for (int i = 0; i < numSamples; i++) { + float fadedSample = ((float)i / (float)numSamples) * (float)samples[i]; + samples[i] = (int16_t)fadedSample; + } + } } From 69fdea36216e0f957fb3812dd0ee84046243ce86 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Fri, 10 Mar 2017 11:44:53 -0800 Subject: [PATCH 07/18] fix typo in comment --- libraries/audio-client/src/AudioNoiseGate.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/audio-client/src/AudioNoiseGate.cpp b/libraries/audio-client/src/AudioNoiseGate.cpp index 45a70c4a28..5224849c5b 100644 --- a/libraries/audio-client/src/AudioNoiseGate.cpp +++ b/libraries/audio-client/src/AudioNoiseGate.cpp @@ -155,7 +155,7 @@ void AudioNoiseGate::gateSamples(int16_t* samples, int numSamples) { } if (!_isOpen) { if (_closedInLastFrame) { - // would be nice to do a little crossfade from silence + // would be nice to do a little crossfade to silence for (int i = 0; i < numSamples; i++) { float fadedSample = (1.0f - (float)i / (float)numSamples) * (float)samples[i]; samples[i] = (int16_t)fadedSample; From eaea718de1994149d5a2bb774bc60f88bbc98cc7 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Fri, 10 Mar 2017 17:08:19 -0800 Subject: [PATCH 08/18] add various scriping interfaces for managing the audio scope and detecting noise gate transitions --- interface/src/Application.cpp | 8 ++++++++ interface/src/audio/AudioScope.cpp | 14 ++++++++------ interface/src/audio/AudioScope.h | 9 +++++++-- libraries/audio-client/src/AudioClient.cpp | 8 ++++++++ libraries/audio-client/src/AudioClient.h | 2 ++ libraries/audio-client/src/AudioNoiseGate.cpp | 9 +++++---- libraries/audio-client/src/AudioNoiseGate.h | 2 ++ .../script-engine/src/AudioScriptingInterface.h | 11 +++++++---- 8 files changed, 47 insertions(+), 16 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index f870bd9f83..7e3f61e0ec 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1182,6 +1182,10 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo // set the local loopback interface for local sounds AudioInjector::setLocalAudioInterface(audioIO.data()); AudioScriptingInterface::getInstance().setLocalAudioInterface(audioIO.data()); + connect(audioIO.data(), &AudioClient::noiseGateOpened, &AudioScriptingInterface::getInstance(), &AudioScriptingInterface::noiseGateOpened); + connect(audioIO.data(), &AudioClient::noiseGateClosed, &AudioScriptingInterface::getInstance(), &AudioScriptingInterface::noiseGateClosed); + connect(audioIO.data(), &AudioClient::inputReceived, &AudioScriptingInterface::getInstance(), &AudioScriptingInterface::inputReceived); + this->installEventFilter(this); @@ -1947,6 +1951,9 @@ void Application::initializeUi() { rootContext->setContextProperty("ApplicationInterface", this); rootContext->setContextProperty("Audio", &AudioScriptingInterface::getInstance()); rootContext->setContextProperty("AudioStats", DependencyManager::get()->getStats().data()); + //rootContext->setContextProperty("AudioScope", DependencyManager::get.data()); + + rootContext->setContextProperty("Controller", DependencyManager::get().data()); rootContext->setContextProperty("Entities", DependencyManager::get().data()); _fileDownload = new FileScriptingInterface(engine); @@ -5521,6 +5528,7 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri scriptEngine->registerGlobalObject("Settings", SettingsScriptingInterface::getInstance()); scriptEngine->registerGlobalObject("AudioDevice", AudioDeviceScriptingInterface::getInstance()); scriptEngine->registerGlobalObject("AudioStats", DependencyManager::get()->getStats().data()); + scriptEngine->registerGlobalObject("AudioScope", DependencyManager::get().data()); // Caches scriptEngine->registerGlobalObject("AnimationCache", DependencyManager::get().data()); diff --git a/interface/src/audio/AudioScope.cpp b/interface/src/audio/AudioScope.cpp index 346fbd11f4..cf9984e32b 100644 --- a/interface/src/audio/AudioScope.cpp +++ b/interface/src/audio/AudioScope.cpp @@ -52,12 +52,14 @@ AudioScope::AudioScope() : connect(audioIO.data(), &AudioClient::inputReceived, this, &AudioScope::addInputToScope); } -void AudioScope::toggle() { - _isEnabled = !_isEnabled; - if (_isEnabled) { - allocateScope(); - } else { - freeScope(); +void AudioScope::setVisible(bool visible) { + if (_isEnabled != visible) { + _isEnabled = visible; + if (_isEnabled) { + allocateScope(); + } else { + freeScope(); + } } } diff --git a/interface/src/audio/AudioScope.h b/interface/src/audio/AudioScope.h index 0b716d7666..615bdaf17f 100644 --- a/interface/src/audio/AudioScope.h +++ b/interface/src/audio/AudioScope.h @@ -34,8 +34,14 @@ public: void render(RenderArgs* renderArgs, int width, int height); public slots: - void toggle(); + void toggle() { setVisible(!_isEnabled); } + void setVisible(bool visible); + bool getVisible() const { return _isEnabled; } + void togglePause() { _isPaused = !_isPaused; } + void setPause(bool paused) { _isPaused = paused; } + bool getPause() { return _isPaused; } + void selectAudioScopeFiveFrames(); void selectAudioScopeTwentyFrames(); void selectAudioScopeFiftyFrames(); @@ -74,7 +80,6 @@ private: int _inputID; int _outputLeftID; int _outputRightD; - }; #endif // hifi_AudioScope_h diff --git a/libraries/audio-client/src/AudioClient.cpp b/libraries/audio-client/src/AudioClient.cpp index 9cd87d2e70..6d135dc571 100644 --- a/libraries/audio-client/src/AudioClient.cpp +++ b/libraries/audio-client/src/AudioClient.cpp @@ -1024,6 +1024,7 @@ void AudioClient::handleAudioInput() { if (_inputGate.clippedInLastFrame()) { _timeSinceLastClip = 0.0f; } + } else { float loudness = 0.0f; @@ -1041,6 +1042,13 @@ void AudioClient::handleAudioInput() { emit inputReceived({ reinterpret_cast(networkAudioSamples), numNetworkBytes }); + if (_inputGate.openedInLastFrame()) { + emit noiseGateOpened(); + } + if (_inputGate.closedInLastFrame()) { + emit noiseGateClosed(); + } + } else { // our input loudness is 0, since we're muted _lastInputLoudness = 0; diff --git a/libraries/audio-client/src/AudioClient.h b/libraries/audio-client/src/AudioClient.h index 5619051eaf..57b19acceb 100644 --- a/libraries/audio-client/src/AudioClient.h +++ b/libraries/audio-client/src/AudioClient.h @@ -218,6 +218,8 @@ signals: void inputReceived(const QByteArray& inputSamples); void outputBytesToNetwork(int numBytes); void inputBytesFromNetwork(int numBytes); + void noiseGateOpened(); + void noiseGateClosed(); void changeDevice(const QAudioDeviceInfo& outputDeviceInfo); void deviceChanged(); diff --git a/libraries/audio-client/src/AudioNoiseGate.cpp b/libraries/audio-client/src/AudioNoiseGate.cpp index 5224849c5b..17bbd1a509 100644 --- a/libraries/audio-client/src/AudioNoiseGate.cpp +++ b/libraries/audio-client/src/AudioNoiseGate.cpp @@ -141,15 +141,16 @@ void AudioNoiseGate::gateSamples(int16_t* samples, int numSamples) { } - bool isOpeningGate = false; + _closedInLastFrame = false; + _openedInLastFrame = false; if (samplesOverNoiseGate > NOISE_GATE_WIDTH) { - isOpeningGate = !_isOpen; + _openedInLastFrame = !_isOpen; _isOpen = true; _framesToClose = NOISE_GATE_CLOSE_FRAME_DELAY; } else { if (--_framesToClose == 0) { - _closedInLastFrame = !_isOpen; + _closedInLastFrame = _isOpen; _isOpen = false; } } @@ -166,7 +167,7 @@ void AudioNoiseGate::gateSamples(int16_t* samples, int numSamples) { _lastLoudness = 0; } - if (isOpeningGate) { + if (_openedInLastFrame) { // would be nice to do a little crossfade from silence for (int i = 0; i < numSamples; i++) { float fadedSample = ((float)i / (float)numSamples) * (float)samples[i]; diff --git a/libraries/audio-client/src/AudioNoiseGate.h b/libraries/audio-client/src/AudioNoiseGate.h index 774a4157bb..ba1ab8599c 100644 --- a/libraries/audio-client/src/AudioNoiseGate.h +++ b/libraries/audio-client/src/AudioNoiseGate.h @@ -25,6 +25,7 @@ public: bool clippedInLastFrame() const { return _didClipInLastFrame; } bool closedInLastFrame() const { return _closedInLastFrame; } + bool openedInLastFrame() const { return _openedInLastFrame; } float getMeasuredFloor() const { return _measuredFloor; } float getLastLoudness() const { return _lastLoudness; } @@ -42,6 +43,7 @@ private: int _sampleCounter; bool _isOpen; bool _closedInLastFrame { false }; + bool _openedInLastFrame { false }; int _framesToClose; }; diff --git a/libraries/script-engine/src/AudioScriptingInterface.h b/libraries/script-engine/src/AudioScriptingInterface.h index 07a6b171f4..6cce78d48f 100644 --- a/libraries/script-engine/src/AudioScriptingInterface.h +++ b/libraries/script-engine/src/AudioScriptingInterface.h @@ -32,10 +32,13 @@ protected: Q_INVOKABLE void setStereoInput(bool stereo); signals: - void mutedByMixer(); - void environmentMuted(); - void receivedFirstPacket(); - void disconnected(); + void mutedByMixer(); /// the client has been muted by the mixer + void environmentMuted(); /// the entire environment has been muted by the mixer + void receivedFirstPacket(); /// the client has received its first packet from the audio mixer + void disconnected(); /// the client has been disconnected from the audio mixer + void noiseGateOpened(); /// the noise gate has opened + void noiseGateClosed(); /// the noise gate has closed + void inputReceived(const QByteArray& inputSamples); /// a frame of mic input audio has been received and processed private: AudioScriptingInterface(); From 5f3ee2e98f1285f64d392b07d8832caf5b9aa95b Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Fri, 10 Mar 2017 17:08:54 -0800 Subject: [PATCH 09/18] add a basic tablet app for the audio scope --- scripts/system/audioScope.js | 97 ++++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 scripts/system/audioScope.js diff --git a/scripts/system/audioScope.js b/scripts/system/audioScope.js new file mode 100644 index 0000000000..0bcff7d5be --- /dev/null +++ b/scripts/system/audioScope.js @@ -0,0 +1,97 @@ +"use strict"; +// +// audioScope.js +// scripts/system/ +// +// Created by Brad Hefta-Gaub on 3/10/2016 +// Copyright 2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +/* global Script, Tablet, AudioScope, Audio */ + +(function () { // BEGIN LOCAL_SCOPE + + var framesSinceOpened = 0; + var scopeVisibile = AudioScope.getVisible(); + var scopePaused = AudioScope.getPause(); + var autoPause = false; + + var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); + var showScopeButton = tablet.addButton({ + icon: "http://s3.amazonaws.com/hifi-public/tony/icons/star.png", + text: "Audio Scope", + isActive: scopeVisibile + }); + + var pauseScopeButton = tablet.addButton({ + icon: "http://s3.amazonaws.com/hifi-public/tony/icons/star.png", + text: "Pause", + isActive: scopePaused + }); + + var autoPauseScopeButton = tablet.addButton({ + icon: "http://s3.amazonaws.com/hifi-public/tony/icons/star.png", + text: "Auto Pause", + isActive: autoPause + }); + + function setScopePause(paused) { + scopePaused = paused; + pauseScopeButton.editProperties({ + isActive: scopePaused, + text: scopePaused ? "Unpause" : "Pause" + }); + AudioScope.setPause(scopePaused); + } + + showScopeButton.clicked.connect(function () { + // toggle button active state + scopeVisibile = !scopeVisibile; + showScopeButton.editProperties({ + isActive: scopeVisibile + }); + + AudioScope.setVisible(scopeVisibile); + }); + + pauseScopeButton.clicked.connect(function () { + // toggle button active state + setScopePause(!scopePaused); + }); + + autoPauseScopeButton.clicked.connect(function () { + // toggle button active state + autoPause = !autoPause; + autoPauseScopeButton.editProperties({ + isActive: autoPause, + text: autoPause ? "Auto Pause" : "Manual" + }); + }); + + Script.scriptEnding.connect(function () { + tablet.removeButton(showScopeButton); + tablet.removeButton(pauseScopeButton); + tablet.removeButton(autoPauseScopeButton); + }); + + Audio.noiseGateOpened.connect(function(){ + framesSinceOpened = 0; + }); + + Audio.noiseGateClosed.connect(function(){ + // noise gate closed + }); + + Audio.inputReceived.connect(function(){ + if (autoPause && AudioScope.getVisible()) { + framesSinceOpened++; + if (framesSinceOpened > 50) { + setScopePause(true); + } + } + }); + + +}()); // END LOCAL_SCOPE \ No newline at end of file From b8a2525f9e04a7c8bec8c56463f089d15375daa9 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Fri, 10 Mar 2017 17:38:00 -0800 Subject: [PATCH 10/18] add auto pause/resume to the Audio Scope App --- scripts/system/audioScope.js | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/scripts/system/audioScope.js b/scripts/system/audioScope.js index 0bcff7d5be..85060173d4 100644 --- a/scripts/system/audioScope.js +++ b/scripts/system/audioScope.js @@ -13,7 +13,6 @@ (function () { // BEGIN LOCAL_SCOPE - var framesSinceOpened = 0; var scopeVisibile = AudioScope.getVisible(); var scopePaused = AudioScope.getPause(); var autoPause = false; @@ -77,21 +76,16 @@ }); Audio.noiseGateOpened.connect(function(){ - framesSinceOpened = 0; + if (autoPause) { + setScopePause(false); + } }); Audio.noiseGateClosed.connect(function(){ // noise gate closed - }); - - Audio.inputReceived.connect(function(){ - if (autoPause && AudioScope.getVisible()) { - framesSinceOpened++; - if (framesSinceOpened > 50) { - setScopePause(true); - } + if (autoPause) { + setScopePause(true); } }); - }()); // END LOCAL_SCOPE \ No newline at end of file From 7eb4b8f5f73f8c39c5cdc5219d96c2555a196c25 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Fri, 10 Mar 2017 17:38:13 -0800 Subject: [PATCH 11/18] expose AudioScope to QML --- interface/src/Application.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 7e3f61e0ec..645c6ab15f 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1951,7 +1951,7 @@ void Application::initializeUi() { rootContext->setContextProperty("ApplicationInterface", this); rootContext->setContextProperty("Audio", &AudioScriptingInterface::getInstance()); rootContext->setContextProperty("AudioStats", DependencyManager::get()->getStats().data()); - //rootContext->setContextProperty("AudioScope", DependencyManager::get.data()); + rootContext->setContextProperty("AudioScope", DependencyManager::get().data()); rootContext->setContextProperty("Controller", DependencyManager::get().data()); From 23e47f2fdc8de48290a0a7dd8f0847213b2e121c Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Fri, 10 Mar 2017 18:13:35 -0800 Subject: [PATCH 12/18] added icons to the audioScope app --- .../icons/tablet-icons/scope-auto.svg | 46 +++++++++++++++++++ .../icons/tablet-icons/scope-pause.svg | 30 ++++++++++++ .../icons/tablet-icons/scope-play.svg | 30 ++++++++++++ scripts/system/audioScope.js | 12 +++-- 4 files changed, 114 insertions(+), 4 deletions(-) create mode 100644 interface/resources/icons/tablet-icons/scope-auto.svg create mode 100644 interface/resources/icons/tablet-icons/scope-pause.svg create mode 100644 interface/resources/icons/tablet-icons/scope-play.svg diff --git a/interface/resources/icons/tablet-icons/scope-auto.svg b/interface/resources/icons/tablet-icons/scope-auto.svg new file mode 100644 index 0000000000..85ef3f0e38 --- /dev/null +++ b/interface/resources/icons/tablet-icons/scope-auto.svg @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/interface/resources/icons/tablet-icons/scope-pause.svg b/interface/resources/icons/tablet-icons/scope-pause.svg new file mode 100644 index 0000000000..3fe74fcc9f --- /dev/null +++ b/interface/resources/icons/tablet-icons/scope-pause.svg @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + diff --git a/interface/resources/icons/tablet-icons/scope-play.svg b/interface/resources/icons/tablet-icons/scope-play.svg new file mode 100644 index 0000000000..56d90ef38a --- /dev/null +++ b/interface/resources/icons/tablet-icons/scope-play.svg @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + diff --git a/scripts/system/audioScope.js b/scripts/system/audioScope.js index 85060173d4..81d8e8fbd4 100644 --- a/scripts/system/audioScope.js +++ b/scripts/system/audioScope.js @@ -19,19 +19,22 @@ var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); var showScopeButton = tablet.addButton({ - icon: "http://s3.amazonaws.com/hifi-public/tony/icons/star.png", + icon: "icons/tablet-icons/scope.svg", text: "Audio Scope", isActive: scopeVisibile }); + var scopePauseImage = "icons/tablet-icons/scope-pause.svg"; + var scopePlayImage = "icons/tablet-icons/scope-play.svg"; + var pauseScopeButton = tablet.addButton({ - icon: "http://s3.amazonaws.com/hifi-public/tony/icons/star.png", - text: "Pause", + icon: scopePaused ? scopePlayImage : scopePauseImage, + text: scopePaused ? "Unpause" : "Pause", isActive: scopePaused }); var autoPauseScopeButton = tablet.addButton({ - icon: "http://s3.amazonaws.com/hifi-public/tony/icons/star.png", + icon: "icons/tablet-icons/scope-auto.svg", text: "Auto Pause", isActive: autoPause }); @@ -40,6 +43,7 @@ scopePaused = paused; pauseScopeButton.editProperties({ isActive: scopePaused, + icon: scopePaused ? scopePlayImage : scopePauseImage, text: scopePaused ? "Unpause" : "Pause" }); AudioScope.setPause(scopePaused); From aa65f03509f9a56f5e060c1e95025283b78b377f Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Fri, 10 Mar 2017 18:14:00 -0800 Subject: [PATCH 13/18] fix mac warning and remove accidentally added whitespace --- assignment-client/src/avatars/AvatarMixer.cpp | 1 - interface/src/Application.cpp | 1 - 2 files changed, 2 deletions(-) diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index c10a616818..d2bfdde7ea 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -37,7 +37,6 @@ const QString AVATAR_MIXER_LOGGING_NAME = "avatar-mixer"; // FIXME - what we'd actually like to do is send to users at ~50% of their present rate down to 30hz. Assume 90 for now. const int AVATAR_MIXER_BROADCAST_FRAMES_PER_SECOND = 45; -const unsigned int AVATAR_DATA_SEND_INTERVAL_MSECS = (1.0f / (float) AVATAR_MIXER_BROADCAST_FRAMES_PER_SECOND) * 1000; AvatarMixer::AvatarMixer(ReceivedMessage& message) : ThreadedAssignment(message) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 645c6ab15f..60d9e815f6 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1953,7 +1953,6 @@ void Application::initializeUi() { rootContext->setContextProperty("AudioStats", DependencyManager::get()->getStats().data()); rootContext->setContextProperty("AudioScope", DependencyManager::get().data()); - rootContext->setContextProperty("Controller", DependencyManager::get().data()); rootContext->setContextProperty("Entities", DependencyManager::get().data()); _fileDownload = new FileScriptingInterface(engine); From 6ce50269ac62278f13d1d4253b0427b575234766 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Fri, 10 Mar 2017 18:42:18 -0800 Subject: [PATCH 14/18] add audio mixer in/out stats to the client stats --- interface/resources/qml/Stats.qml | 10 ++++++++++ interface/src/ui/Stats.cpp | 6 ++++++ interface/src/ui/Stats.h | 10 ++++++++++ 3 files changed, 26 insertions(+) diff --git a/interface/resources/qml/Stats.qml b/interface/resources/qml/Stats.qml index 58d589b667..ec170dfd08 100644 --- a/interface/resources/qml/Stats.qml +++ b/interface/resources/qml/Stats.qml @@ -181,6 +181,16 @@ Item { root.avatarMixerOutPps + "pps, " + root.myAvatarSendRate.toFixed(2) + "hz"; } + StatText { + visible: root.expanded; + text: "Audio Mixer In: " + root.audioMixerInKbps + " kbps, " + + root.audioMixerInPps + "pps"; + } + StatText { + visible: root.expanded; + text: "Audio Mixer Out: " + root.audioMixerOutKbps + " kbps, " + + root.audioMixerOutPps + "pps"; + } StatText { visible: root.expanded; text: "Downloads: " + root.downloads + "/" + root.downloadLimit + diff --git a/interface/src/ui/Stats.cpp b/interface/src/ui/Stats.cpp index 1075bbdaa4..038dcd42cc 100644 --- a/interface/src/ui/Stats.cpp +++ b/interface/src/ui/Stats.cpp @@ -214,6 +214,12 @@ void Stats::updateStats(bool force) { STAT_UPDATE(audioMixerPps, roundf( bandwidthRecorder->getAverageInputPacketsPerSecond(NodeType::AudioMixer) + bandwidthRecorder->getAverageOutputPacketsPerSecond(NodeType::AudioMixer))); + + STAT_UPDATE(audioMixerInKbps, roundf(bandwidthRecorder->getAverageInputKilobitsPerSecond(NodeType::AudioMixer))); + STAT_UPDATE(audioMixerInPps, roundf(bandwidthRecorder->getAverageInputPacketsPerSecond(NodeType::AudioMixer))); + STAT_UPDATE(audioMixerOutKbps, roundf(bandwidthRecorder->getAverageOutputKilobitsPerSecond(NodeType::AudioMixer))); + STAT_UPDATE(audioMixerOutPps, roundf(bandwidthRecorder->getAverageOutputPacketsPerSecond(NodeType::AudioMixer))); + } else { STAT_UPDATE(audioMixerKbps, -1); STAT_UPDATE(audioMixerPps, -1); diff --git a/interface/src/ui/Stats.h b/interface/src/ui/Stats.h index 6be084100c..96c5d374d3 100644 --- a/interface/src/ui/Stats.h +++ b/interface/src/ui/Stats.h @@ -70,6 +70,12 @@ class Stats : public QQuickItem { STATS_PROPERTY(int, avatarMixerOutKbps, 0) STATS_PROPERTY(int, avatarMixerOutPps, 0) STATS_PROPERTY(float, myAvatarSendRate, 0) + + STATS_PROPERTY(int, audioMixerInKbps, 0) + STATS_PROPERTY(int, audioMixerInPps, 0) + STATS_PROPERTY(int, audioMixerOutKbps, 0) + STATS_PROPERTY(int, audioMixerOutPps, 0) + STATS_PROPERTY(int, audioMixerKbps, 0) STATS_PROPERTY(int, audioMixerPps, 0) STATS_PROPERTY(int, downloads, 0) @@ -180,6 +186,10 @@ signals: void avatarMixerOutKbpsChanged(); void avatarMixerOutPpsChanged(); void myAvatarSendRateChanged(); + void audioMixerInKbpsChanged(); + void audioMixerInPpsChanged(); + void audioMixerOutKbpsChanged(); + void audioMixerOutPpsChanged(); void audioMixerKbpsChanged(); void audioMixerPpsChanged(); void downloadsChanged(); From a38965d628b09dfe179c1dccef4c56059a8e37fb Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Sat, 11 Mar 2017 09:50:30 -0800 Subject: [PATCH 15/18] add more audio stats --- interface/resources/qml/Stats.qml | 15 ++++++++++ interface/src/ui/Stats.cpp | 21 ++++++++++++-- interface/src/ui/Stats.h | 15 +++++++++- libraries/audio-client/src/AudioClient.cpp | 14 ++++++++++ libraries/audio-client/src/AudioClient.h | 14 ++++++++++ libraries/audio-client/src/AudioNoiseGate.h | 1 + libraries/shared/src/shared/RateCounter.h | 31 ++++++++++++--------- 7 files changed, 94 insertions(+), 17 deletions(-) diff --git a/interface/resources/qml/Stats.qml b/interface/resources/qml/Stats.qml index ec170dfd08..564c74b526 100644 --- a/interface/resources/qml/Stats.qml +++ b/interface/resources/qml/Stats.qml @@ -186,11 +186,26 @@ Item { text: "Audio Mixer In: " + root.audioMixerInKbps + " kbps, " + root.audioMixerInPps + "pps"; } + StatText { + visible: root.expanded; + text: "Audio In Audio: " + root.audioAudioInboundPPS + " pps, " + + "Silent: " + root.audioSilentInboundPPS + " pps"; + } StatText { visible: root.expanded; text: "Audio Mixer Out: " + root.audioMixerOutKbps + " kbps, " + root.audioMixerOutPps + "pps"; } + StatText { + visible: root.expanded; + text: "Audio Out Mic: " + root.audioMicOutboundPPS + " pps, " + + "Silent: " + root.audioSilentOutboundPPS + " pps"; + } + StatText { + visible: root.expanded; + text: "Audio Codec: " + root.audioCodec + " Noise Gate: " + + root.audioNoiseGate; + } StatText { visible: root.expanded; text: "Downloads: " + root.downloads + "/" + root.downloadLimit + diff --git a/interface/src/ui/Stats.cpp b/interface/src/ui/Stats.cpp index 038dcd42cc..923d9f642d 100644 --- a/interface/src/ui/Stats.cpp +++ b/interface/src/ui/Stats.cpp @@ -198,15 +198,16 @@ void Stats::updateStats(bool force) { STAT_UPDATE(avatarMixerInPps, roundf(bandwidthRecorder->getAverageInputPacketsPerSecond(NodeType::AvatarMixer))); STAT_UPDATE(avatarMixerOutKbps, roundf(bandwidthRecorder->getAverageOutputKilobitsPerSecond(NodeType::AvatarMixer))); STAT_UPDATE(avatarMixerOutPps, roundf(bandwidthRecorder->getAverageOutputPacketsPerSecond(NodeType::AvatarMixer))); - STAT_UPDATE(myAvatarSendRate, avatarManager->getMyAvatarSendRate()); } else { STAT_UPDATE(avatarMixerInKbps, -1); STAT_UPDATE(avatarMixerInPps, -1); STAT_UPDATE(avatarMixerOutKbps, -1); STAT_UPDATE(avatarMixerOutPps, -1); - STAT_UPDATE(myAvatarSendRate, avatarManager->getMyAvatarSendRate()); } + STAT_UPDATE(myAvatarSendRate, avatarManager->getMyAvatarSendRate()); + SharedNodePointer audioMixerNode = nodeList->soloNodeOfType(NodeType::AudioMixer); + auto audioClient = DependencyManager::get(); if (audioMixerNode || force) { STAT_UPDATE(audioMixerKbps, roundf( bandwidthRecorder->getAverageInputKilobitsPerSecond(NodeType::AudioMixer) + @@ -219,11 +220,25 @@ void Stats::updateStats(bool force) { STAT_UPDATE(audioMixerInPps, roundf(bandwidthRecorder->getAverageInputPacketsPerSecond(NodeType::AudioMixer))); STAT_UPDATE(audioMixerOutKbps, roundf(bandwidthRecorder->getAverageOutputKilobitsPerSecond(NodeType::AudioMixer))); STAT_UPDATE(audioMixerOutPps, roundf(bandwidthRecorder->getAverageOutputPacketsPerSecond(NodeType::AudioMixer))); - + STAT_UPDATE(audioMicOutboundPPS, audioClient->getMicAudioOutboundPPS()); + STAT_UPDATE(audioSilentOutboundPPS, audioClient->getSilentOutboundPPS()); + STAT_UPDATE(audioAudioInboundPPS, audioClient->getAudioInboundPPS()); + STAT_UPDATE(audioSilentInboundPPS, audioClient->getSilentInboundPPS()); } else { STAT_UPDATE(audioMixerKbps, -1); STAT_UPDATE(audioMixerPps, -1); + STAT_UPDATE(audioMixerInKbps, -1); + STAT_UPDATE(audioMixerInPps, -1); + STAT_UPDATE(audioMixerOutKbps, -1); + STAT_UPDATE(audioMixerOutPps, -1); + STAT_UPDATE(audioMicOutboundPPS, -1); + STAT_UPDATE(audioSilentOutboundPPS, -1); + STAT_UPDATE(audioAudioInboundPPS, -1); + STAT_UPDATE(audioSilentInboundPPS, -1); } + STAT_UPDATE(audioCodec, audioClient->getSelectedAudioFormat()); + STAT_UPDATE(audioNoiseGate, audioClient->getNoiseGateOpen() ? "Open" : "Closed"); + auto loadingRequests = ResourceCache::getLoadingRequests(); STAT_UPDATE(downloads, loadingRequests.size()); diff --git a/interface/src/ui/Stats.h b/interface/src/ui/Stats.h index 96c5d374d3..0ce113e0a0 100644 --- a/interface/src/ui/Stats.h +++ b/interface/src/ui/Stats.h @@ -75,9 +75,15 @@ class Stats : public QQuickItem { STATS_PROPERTY(int, audioMixerInPps, 0) STATS_PROPERTY(int, audioMixerOutKbps, 0) STATS_PROPERTY(int, audioMixerOutPps, 0) - STATS_PROPERTY(int, audioMixerKbps, 0) STATS_PROPERTY(int, audioMixerPps, 0) + STATS_PROPERTY(int, audioMicOutboundPPS, 0) + STATS_PROPERTY(int, audioSilentOutboundPPS, 0) + STATS_PROPERTY(int, audioAudioInboundPPS, 0) + STATS_PROPERTY(int, audioSilentInboundPPS, 0) + STATS_PROPERTY(QString, audioCodec, QString()) + STATS_PROPERTY(QString, audioNoiseGate, QString()) + STATS_PROPERTY(int, downloads, 0) STATS_PROPERTY(int, downloadLimit, 0) STATS_PROPERTY(int, downloadsPending, 0) @@ -192,6 +198,13 @@ signals: void audioMixerOutPpsChanged(); void audioMixerKbpsChanged(); void audioMixerPpsChanged(); + void audioMicOutboundPPSChanged(); + void audioSilentOutboundPPSChanged(); + void audioAudioInboundPPSChanged(); + void audioSilentInboundPPSChanged(); + void audioCodecChanged(); + void audioNoiseGateChanged(); + void downloadsChanged(); void downloadLimitChanged(); void downloadsPendingChanged(); diff --git a/libraries/audio-client/src/AudioClient.cpp b/libraries/audio-client/src/AudioClient.cpp index 6d135dc571..9fb8bae6ca 100644 --- a/libraries/audio-client/src/AudioClient.cpp +++ b/libraries/audio-client/src/AudioClient.cpp @@ -608,6 +608,13 @@ void AudioClient::handleAudioEnvironmentDataPacket(QSharedPointer message) { + + if (message->getType() == PacketType::SilentAudioFrame) { + _silentInbound.increment(); + } else { + _audioInbound.increment(); + } + auto nodeList = DependencyManager::get(); nodeList->flagTimeForConnectionStep(LimitedNodeList::ConnectionStep::ReceiveFirstAudioPacket); @@ -1067,7 +1074,11 @@ void AudioClient::handleAudioInput() { // have _lastInputLoudness of 0 in our NEXT frame, we will send a silent packet if (_lastInputLoudness == 0 && !_inputGate.closedInLastFrame()) { packetType = PacketType::SilentAudioFrame; + _silentOutbound.increment(); + } else { + _micAudioOutbound.increment(); } + Transform audioTransform; audioTransform.setTranslation(_positionGetter()); audioTransform.setRotation(_orientationGetter()); @@ -1092,6 +1103,7 @@ void AudioClient::handleAudioInput() { } } +// FIXME - should this go through the noise gate and honor mute and echo? void AudioClient::handleRecordedAudioInput(const QByteArray& audio) { Transform audioTransform; audioTransform.setTranslation(_positionGetter()); @@ -1104,6 +1116,8 @@ void AudioClient::handleRecordedAudioInput(const QByteArray& audio) { encodedBuffer = audio; } + _micAudioOutbound.increment(); + // FIXME check a flag to see if we should echo audio? emitAudioPacket(encodedBuffer.data(), encodedBuffer.size(), _outgoingAvatarAudioSequenceNumber, audioTransform, avatarBoundingBoxCorner, avatarBoundingBoxScale, diff --git a/libraries/audio-client/src/AudioClient.h b/libraries/audio-client/src/AudioClient.h index 57b19acceb..512b4bb3c1 100644 --- a/libraries/audio-client/src/AudioClient.h +++ b/libraries/audio-client/src/AudioClient.h @@ -46,6 +46,8 @@ #include #include +#include + #include #include "AudioIOStats.h" @@ -121,6 +123,13 @@ public: void negotiateAudioFormat(); void selectAudioFormat(const QString& selectedCodecName); + Q_INVOKABLE QString getSelectedAudioFormat() const { return _selectedCodecName; } + Q_INVOKABLE bool getNoiseGateOpen() const { return _inputGate.isOpen(); } + Q_INVOKABLE float getSilentOutboundPPS() const { return _silentOutbound.rate(); } + Q_INVOKABLE float getMicAudioOutboundPPS() const { return _micAudioOutbound.rate(); } + Q_INVOKABLE float getSilentInboundPPS() const { return _silentInbound.rate(); } + Q_INVOKABLE float getAudioInboundPPS() const { return _audioInbound.rate(); } + const MixedProcessedAudioStream& getReceivedAudioStream() const { return _receivedAudioStream; } MixedProcessedAudioStream& getReceivedAudioStream() { return _receivedAudioStream; } @@ -384,6 +393,11 @@ private: Encoder* _encoder { nullptr }; // for outbound mic stream QThread* _checkDevicesThread { nullptr }; + + RateCounter<> _silentOutbound; + RateCounter<> _micAudioOutbound; + RateCounter<> _silentInbound; + RateCounter<> _audioInbound; }; diff --git a/libraries/audio-client/src/AudioNoiseGate.h b/libraries/audio-client/src/AudioNoiseGate.h index ba1ab8599c..fb31561994 100644 --- a/libraries/audio-client/src/AudioNoiseGate.h +++ b/libraries/audio-client/src/AudioNoiseGate.h @@ -26,6 +26,7 @@ public: bool clippedInLastFrame() const { return _didClipInLastFrame; } bool closedInLastFrame() const { return _closedInLastFrame; } bool openedInLastFrame() const { return _openedInLastFrame; } + bool isOpen() const { return _isOpen; } float getMeasuredFloor() const { return _measuredFloor; } float getLastLoudness() const { return _lastLoudness; } diff --git a/libraries/shared/src/shared/RateCounter.h b/libraries/shared/src/shared/RateCounter.h index d04d87493a..3cf509b6bf 100644 --- a/libraries/shared/src/shared/RateCounter.h +++ b/libraries/shared/src/shared/RateCounter.h @@ -24,29 +24,34 @@ public: RateCounter() { _rate = 0; } // avoid use of std::atomic copy ctor void increment(size_t count = 1) { - auto now = usecTimestampNow(); - float currentIntervalMs = (now - _start) / (float) USECS_PER_MSEC; - if (currentIntervalMs > (float) INTERVAL) { - float currentCount = _count; - float intervalSeconds = currentIntervalMs / (float) MSECS_PER_SECOND; - _rate = roundf(currentCount / intervalSeconds * _scale) / _scale; - _start = now; - _count = 0; - }; + checkRate(); _count += count; } - float rate() const { return _rate; } + float rate() const { checkRate(); return _rate; } uint8_t precision() const { return PRECISION; } uint32_t interval() const { return INTERVAL; } private: - uint64_t _start { usecTimestampNow() }; - size_t _count { 0 }; + mutable uint64_t _start { usecTimestampNow() }; + mutable size_t _count { 0 }; const float _scale { powf(10, PRECISION) }; - std::atomic _rate; + mutable std::atomic _rate; + + void checkRate() const { + auto now = usecTimestampNow(); + float currentIntervalMs = (now - _start) / (float)USECS_PER_MSEC; + if (currentIntervalMs > (float)INTERVAL) { + float currentCount = _count; + float intervalSeconds = currentIntervalMs / (float)MSECS_PER_SECOND; + _rate = roundf(currentCount / intervalSeconds * _scale) / _scale; + _start = now; + _count = 0; + }; + } + }; #endif From 3e020ede78ba0584114a0c402f4d93af0ae0fc32 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 13 Mar 2017 11:58:43 -0700 Subject: [PATCH 16/18] CR feedback --- libraries/audio-client/src/AudioClient.cpp | 9 +- libraries/audio-client/src/AudioNoiseGate.cpp | 97 ++++++++++--------- libraries/audio-client/src/AudioNoiseGate.h | 24 ++--- 3 files changed, 68 insertions(+), 62 deletions(-) diff --git a/libraries/audio-client/src/AudioClient.cpp b/libraries/audio-client/src/AudioClient.cpp index 9fb8bae6ca..c32b5600d9 100644 --- a/libraries/audio-client/src/AudioClient.cpp +++ b/libraries/audio-client/src/AudioClient.cpp @@ -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 _lastInputLoudness = _inputGate.getLastLoudness(); - if (_inputGate.clippedInLastFrame()) { + if (_inputGate.clippedInLastBlock()) { _timeSinceLastClip = 0.0f; } @@ -1049,10 +1049,9 @@ void AudioClient::handleAudioInput() { emit inputReceived({ reinterpret_cast(networkAudioSamples), numNetworkBytes }); - if (_inputGate.openedInLastFrame()) { + if (_inputGate.openedInLastBlock()) { emit noiseGateOpened(); - } - if (_inputGate.closedInLastFrame()) { + } else if (_inputGate.closedInLastBlock()) { emit noiseGateClosed(); } @@ -1072,7 +1071,7 @@ void AudioClient::handleAudioInput() { // 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 // 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; _silentOutbound.increment(); } else { diff --git a/libraries/audio-client/src/AudioNoiseGate.cpp b/libraries/audio-client/src/AudioNoiseGate.cpp index 17bbd1a509..2acdea6f0c 100644 --- a/libraries/audio-client/src/AudioNoiseGate.cpp +++ b/libraries/audio-client/src/AudioNoiseGate.cpp @@ -19,16 +19,16 @@ const float AudioNoiseGate::CLIPPING_THRESHOLD = 0.90f; AudioNoiseGate::AudioNoiseGate() : - _inputFrameCounter(0), + _inputBlockCounter(0), _lastLoudness(0.0f), - _quietestFrame(std::numeric_limits::max()), - _loudestFrame(0.0f), - _didClipInLastFrame(false), + _quietestBlock(std::numeric_limits::max()), + _loudestBlock(0.0f), + _didClipInLastBlock(false), _dcOffset(0.0f), _measuredFloor(0.0f), _sampleCounter(0), _isOpen(false), - _framesToClose(0) + _buffersToClose(0) { } @@ -37,7 +37,7 @@ void AudioNoiseGate::removeDCOffset(int16_t* samples, int numSamples) { // // 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 buffers, and remove it from the input signal. // This causes the noise background measurements and server muting to be more accurate. Many off-board // ADC's have a noticeable DC offset. // @@ -51,7 +51,7 @@ void AudioNoiseGate::removeDCOffset(int16_t* samples, int numSamples) { // Update measured DC offset measuredDcOffset /= numSamples; if (_dcOffset == 0.0f) { - // On first frame, copy over measured offset + // On first buffer, copy over measured offset _dcOffset = measuredDcOffset; } else { _dcOffset = DC_OFFSET_AVERAGING * _dcOffset + (1.0f - DC_OFFSET_AVERAGING) * measuredDcOffset; @@ -69,13 +69,13 @@ 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. // 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 buffer for which the height must be exceeded // 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 buffer, how many buffers // 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_BLOCKSS_TO_AVERAGE: How many audio buffers should we average together to compute noise floor. // 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; int thisSample = 0; @@ -83,16 +83,16 @@ void AudioNoiseGate::gateSamples(int16_t* samples, int numSamples) { const float NOISE_GATE_HEIGHT = 7.0f; const int NOISE_GATE_WIDTH = 5; - const int NOISE_GATE_CLOSE_FRAME_DELAY = 5; - const int NOISE_GATE_FRAMES_TO_AVERAGE = 5; + const int NOISE_GATE_CLOSE_BLOCK_DELAY = 5; + const int NOISE_GATE_BLOCKS_TO_AVERAGE = 5; // Check clipping, and check if should open noise gate - _didClipInLastFrame = false; + _didClipInLastBlock = false; for (int i = 0; i < numSamples; i++) { thisSample = std::abs(samples[i]); if (thisSample >= ((float) AudioConstants::MAX_SAMPLE_VALUE * CLIPPING_THRESHOLD)) { - _didClipInLastFrame = true; + _didClipInLastBlock = true; } loudness += thisSample; @@ -104,61 +104,64 @@ void AudioNoiseGate::gateSamples(int16_t* samples, int numSamples) { _lastLoudness = fabs(loudness / numSamples); - if (_quietestFrame > _lastLoudness) { - _quietestFrame = _lastLoudness; + if (_quietestBlock > _lastLoudness) { + _quietestBlock = _lastLoudness; } - if (_loudestFrame < _lastLoudness) { - _loudestFrame = _lastLoudness; + if (_loudestBlock < _lastLoudness) { + _loudestBlock = _lastLoudness; } const int FRAMES_FOR_NOISE_DETECTION = 400; - if (_inputFrameCounter++ > FRAMES_FOR_NOISE_DETECTION) { - _quietestFrame = std::numeric_limits::max(); - _loudestFrame = 0.0f; - _inputFrameCounter = 0; + if (_inputBlockCounter++ > FRAMES_FOR_NOISE_DETECTION) { + _quietestBlock = std::numeric_limits::max(); + _loudestBlock = 0.0f; + _inputBlockCounter = 0; } // If Noise Gate is enabled, check and turn the gate on and off - float averageOfAllSampleFrames = 0.0f; - _sampleFrames[_sampleCounter++] = _lastLoudness; - if (_sampleCounter == NUMBER_OF_NOISE_SAMPLE_FRAMES) { + float averageOfAllSampleBlocks = 0.0f; + _sampleBlocks[_sampleCounter++] = _lastLoudness; + if (_sampleCounter == NUMBER_OF_NOISE_SAMPLE_BLOCKS) { float smallestSample = std::numeric_limits::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; - for (int j = i; j < i + NOISE_GATE_FRAMES_TO_AVERAGE; j++) { - thisAverage += _sampleFrames[j]; - averageOfAllSampleFrames += _sampleFrames[j]; + for (int j = i; j < i + NOISE_GATE_BLOCKS_TO_AVERAGE; j++) { + thisAverage += _sampleBlocks[j]; + averageOfAllSampleBlocks += _sampleBlocks[j]; } - thisAverage /= NOISE_GATE_FRAMES_TO_AVERAGE; + thisAverage /= NOISE_GATE_BLOCKS_TO_AVERAGE; if (thisAverage < smallestSample) { smallestSample = thisAverage; } } - averageOfAllSampleFrames /= NUMBER_OF_NOISE_SAMPLE_FRAMES; + averageOfAllSampleBlocks /= NUMBER_OF_NOISE_SAMPLE_BLOCKS; _measuredFloor = smallestSample; _sampleCounter = 0; } - _closedInLastFrame = false; - _openedInLastFrame = false; + _closedInLastBlock = false; + _openedInLastBlock = false; if (samplesOverNoiseGate > NOISE_GATE_WIDTH) { - _openedInLastFrame = !_isOpen; + _openedInLastBlock = !_isOpen; _isOpen = true; - _framesToClose = NOISE_GATE_CLOSE_FRAME_DELAY; + _buffersToClose = NOISE_GATE_CLOSE_BLOCK_DELAY; } else { - if (--_framesToClose == 0) { - _closedInLastFrame = _isOpen; + if (--_buffersToClose == 0) { + _closedInLastBlock = _isOpen; _isOpen = false; } } if (!_isOpen) { - if (_closedInLastFrame) { - // would be nice to do a little crossfade to silence + // First buffer after being closed gets faded to silence, we fade across + // the entire buffer on fading out. All subsequent buffers are muted by being slammed + // to zeros + if (_closedInLastBlock) { + float fadeSlope = (1.0f / numSamples); 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; } } else { @@ -167,10 +170,14 @@ void AudioNoiseGate::gateSamples(int16_t* samples, int numSamples) { _lastLoudness = 0; } - if (_openedInLastFrame) { - // would be nice to do a little crossfade from silence - for (int i = 0; i < numSamples; i++) { - float fadedSample = ((float)i / (float)numSamples) * (float)samples[i]; + if (_openedInLastBlock) { + // would be nice to do a little crossfade from silence, but we only want to fade + // across the first 1/10th of the buffer, because we don't want to miss early + // 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; } } diff --git a/libraries/audio-client/src/AudioNoiseGate.h b/libraries/audio-client/src/AudioNoiseGate.h index fb31561994..81ef27664d 100644 --- a/libraries/audio-client/src/AudioNoiseGate.h +++ b/libraries/audio-client/src/AudioNoiseGate.h @@ -14,7 +14,7 @@ #include -const int NUMBER_OF_NOISE_SAMPLE_FRAMES = 300; +const int NUMBER_OF_NOISE_SAMPLE_BLOCKS = 300; class AudioNoiseGate { public: @@ -23,9 +23,9 @@ public: void gateSamples(int16_t* samples, int numSamples); void removeDCOffset(int16_t* samples, int numSamples); - bool clippedInLastFrame() const { return _didClipInLastFrame; } - bool closedInLastFrame() const { return _closedInLastFrame; } - bool openedInLastFrame() const { return _openedInLastFrame; } + bool clippedInLastBlock() const { return _didClipInLastBlock; } + bool closedInLastBlock() const { return _closedInLastBlock; } + bool openedInLastBlock() const { return _openedInLastBlock; } bool isOpen() const { return _isOpen; } float getMeasuredFloor() const { return _measuredFloor; } float getLastLoudness() const { return _lastLoudness; } @@ -33,19 +33,19 @@ public: static const float CLIPPING_THRESHOLD; private: - int _inputFrameCounter; + int _inputBlockCounter; float _lastLoudness; - float _quietestFrame; - float _loudestFrame; - bool _didClipInLastFrame; + float _quietestBlock; + float _loudestBlock; + bool _didClipInLastBlock; float _dcOffset; float _measuredFloor; - float _sampleFrames[NUMBER_OF_NOISE_SAMPLE_FRAMES]; + float _sampleBlocks[NUMBER_OF_NOISE_SAMPLE_BLOCKS]; int _sampleCounter; bool _isOpen; - bool _closedInLastFrame { false }; - bool _openedInLastFrame { false }; - int _framesToClose; + bool _closedInLastBlock { false }; + bool _openedInLastBlock { false }; + int _buffersToClose; }; #endif // hifi_AudioNoiseGate_h \ No newline at end of file From 099ee1db7f1ffda4248b3c3a4a4aabfd04b5a8be Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 13 Mar 2017 12:05:42 -0700 Subject: [PATCH 17/18] CR feedback --- libraries/audio-client/src/AudioNoiseGate.cpp | 22 +++++++++---------- libraries/audio-client/src/AudioNoiseGate.h | 2 +- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/libraries/audio-client/src/AudioNoiseGate.cpp b/libraries/audio-client/src/AudioNoiseGate.cpp index 2acdea6f0c..7aef8086a0 100644 --- a/libraries/audio-client/src/AudioNoiseGate.cpp +++ b/libraries/audio-client/src/AudioNoiseGate.cpp @@ -28,7 +28,7 @@ AudioNoiseGate::AudioNoiseGate() : _measuredFloor(0.0f), _sampleCounter(0), _isOpen(false), - _buffersToClose(0) + _blocksToClose(0) { } @@ -37,7 +37,7 @@ void AudioNoiseGate::removeDCOffset(int16_t* samples, int numSamples) { // // DC Offset correction // - // Measure the DC offset over a trailing number of buffers, 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 // ADC's have a noticeable DC offset. // @@ -51,7 +51,7 @@ void AudioNoiseGate::removeDCOffset(int16_t* samples, int numSamples) { // Update measured DC offset measuredDcOffset /= numSamples; if (_dcOffset == 0.0f) { - // On first buffer, copy over measured offset + // On first block, copy over measured offset _dcOffset = measuredDcOffset; } else { _dcOffset = DC_OFFSET_AVERAGING * _dcOffset + (1.0f - DC_OFFSET_AVERAGING) * measuredDcOffset; @@ -69,11 +69,11 @@ 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. // Make this value lower for more sensitivity and less rejection of noise. - // NOISE_GATE_WIDTH: The number of samples in an audio buffer 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. - // NOISE_GATE_CLOSE_BLOCK_DELAY: Once the noise is below the gate height for the buffer, how many buffers + // 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. - // NOISE_GATE_BLOCKSS_TO_AVERAGE: How many audio buffers should we average together to compute noise floor. + // NOISE_GATE_BLOCKSS_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. // NUMBER_OF_NOISE_SAMPLE_BLOCKS: How often should we re-evaluate the noise floor? @@ -147,16 +147,16 @@ void AudioNoiseGate::gateSamples(int16_t* samples, int numSamples) { if (samplesOverNoiseGate > NOISE_GATE_WIDTH) { _openedInLastBlock = !_isOpen; _isOpen = true; - _buffersToClose = NOISE_GATE_CLOSE_BLOCK_DELAY; + _blocksToClose = NOISE_GATE_CLOSE_BLOCK_DELAY; } else { - if (--_buffersToClose == 0) { + if (--_blocksToClose == 0) { _closedInLastBlock = _isOpen; _isOpen = false; } } if (!_isOpen) { - // First buffer after being closed gets faded to silence, we fade across - // the entire buffer on fading out. All subsequent buffers are muted by being slammed + // First block after being closed gets faded to silence, we fade across + // the entire block on fading out. All subsequent blocks are muted by being slammed // to zeros if (_closedInLastBlock) { float fadeSlope = (1.0f / numSamples); @@ -172,7 +172,7 @@ void AudioNoiseGate::gateSamples(int16_t* samples, int numSamples) { if (_openedInLastBlock) { // would be nice to do a little crossfade from silence, but we only want to fade - // across the first 1/10th of the buffer, because we don't want to miss early + // across the first 1/10th of the block, because we don't want to miss early // transients. int fadeSamples = numSamples / 10; // fade over 1/10th of the samples float fadeSlope = (1.0f / fadeSamples); diff --git a/libraries/audio-client/src/AudioNoiseGate.h b/libraries/audio-client/src/AudioNoiseGate.h index 81ef27664d..f72e92b0d5 100644 --- a/libraries/audio-client/src/AudioNoiseGate.h +++ b/libraries/audio-client/src/AudioNoiseGate.h @@ -45,7 +45,7 @@ private: bool _isOpen; bool _closedInLastBlock { false }; bool _openedInLastBlock { false }; - int _buffersToClose; + int _blocksToClose; }; #endif // hifi_AudioNoiseGate_h \ No newline at end of file From 956fdd09339378ae25ecc17a3fbb262d3f0c59ad Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 13 Mar 2017 12:06:38 -0700 Subject: [PATCH 18/18] CR feedback --- libraries/audio-client/src/AudioNoiseGate.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/audio-client/src/AudioNoiseGate.cpp b/libraries/audio-client/src/AudioNoiseGate.cpp index 7aef8086a0..8a9134b5dc 100644 --- a/libraries/audio-client/src/AudioNoiseGate.cpp +++ b/libraries/audio-client/src/AudioNoiseGate.cpp @@ -73,7 +73,7 @@ void AudioNoiseGate::gateSamples(int16_t* samples, int numSamples) { // to open the gate. // 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. - // NOISE_GATE_BLOCKSS_TO_AVERAGE: How many audio blocks 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. // NUMBER_OF_NOISE_SAMPLE_BLOCKS: How often should we re-evaluate the noise floor?