From a1ba36d5438d122796cc0d31fcf04d79eb584589 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Fri, 22 Nov 2013 20:08:44 -0800 Subject: [PATCH 1/6] Lean drive works with keys and no up/down --- interface/src/avatar/MyAvatar.cpp | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 6ec75931c1..12a6bb7f7a 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -459,13 +459,37 @@ void MyAvatar::updateFromGyrosAndOrWebcam(bool turnWithHead) { if (!Menu::getInstance()->isOptionChecked(MenuOption::MoveWithLean)) { return; } + + // Move with Lean by applying thrust proportional to leaning + glm::quat orientation = _head.getCameraOrientation(); + glm::vec3 front = orientation * IDENTITY_FRONT; + glm::vec3 right = orientation * IDENTITY_RIGHT; + + const float LEAN_FWD_DEAD_ZONE = 2.f; + const float LEAN_SIDEWAYS_DEAD_ZONE = 2.f; + const float LEAN_FWD_THRUST_SCALE = 1.f; + const float LEAN_SIDEWAYS_THRUST_SCALE = 1.f; + + //printf("%.2f, %.2f\n", _head.getLeanForward(), _head.getLeanSideways()); + + if (fabs(_head.getLeanForward()) > LEAN_FWD_DEAD_ZONE) { + addThrust(front * -_head.getLeanForward() * LEAN_FWD_THRUST_SCALE); + } + if (fabs(_head.getLeanSideways()) > LEAN_SIDEWAYS_DEAD_ZONE) { + addThrust(right * -_head.getLeanSideways() * LEAN_SIDEWAYS_THRUST_SCALE); + } + +/* const float ANGULAR_DRIVE_SCALE = 0.1f; const float ANGULAR_DEAD_ZONE = 0.3f; + setDriveKeys(FWD, glm::clamp(-_head.getLeanForward() * ANGULAR_DRIVE_SCALE - ANGULAR_DEAD_ZONE, 0.0f, 1.0f)); setDriveKeys(BACK, glm::clamp(_head.getLeanForward() * ANGULAR_DRIVE_SCALE - ANGULAR_DEAD_ZONE, 0.0f, 1.0f)); setDriveKeys(LEFT, glm::clamp(_head.getLeanSideways() * ANGULAR_DRIVE_SCALE - ANGULAR_DEAD_ZONE, 0.0f, 1.0f)); setDriveKeys(RIGHT, glm::clamp(-_head.getLeanSideways() * ANGULAR_DRIVE_SCALE - ANGULAR_DEAD_ZONE, 0.0f, 1.0f)); + */ + /* // only consider going up if we're not going in any of the four horizontal directions if (_driveKeys[FWD] == 0.0f && _driveKeys[BACK] == 0.0f && _driveKeys[LEFT] == 0.0f && _driveKeys[RIGHT] == 0.0f) { const float LINEAR_DRIVE_SCALE = 5.0f; @@ -476,6 +500,7 @@ void MyAvatar::updateFromGyrosAndOrWebcam(bool turnWithHead) { } else { setDriveKeys(UP, 0.0f); } + */ } static TextRenderer* textRenderer() { From 62c882b788682cd05aa1936013b098ce8bf54219 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Mon, 25 Nov 2013 09:44:40 -0800 Subject: [PATCH 2/6] Rounding numbers --- libraries/shared/src/PerfStat.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libraries/shared/src/PerfStat.cpp b/libraries/shared/src/PerfStat.cpp index 267108f87e..cbec4806e5 100644 --- a/libraries/shared/src/PerfStat.cpp +++ b/libraries/shared/src/PerfStat.cpp @@ -113,20 +113,20 @@ PerformanceWarning::~PerformanceWarning() { if ((_alwaysDisplay || _renderWarningsOn) && elapsedmsec > 1) { if (elapsedmsec > 1000) { double elapsedsec = (end - _start) / 1000000.0; - qDebug("%s took %lf seconds %s\n", _message, elapsedsec, (_alwaysDisplay ? "" : "WARNING!") ); + qDebug("%s took %.2lf seconds %s\n", _message, elapsedsec, (_alwaysDisplay ? "" : "WARNING!") ); } else { if (_suppressShortTimings) { if (elapsedmsec > 10) { - qDebug("%s took %lf milliseconds %s\n", _message, elapsedmsec, + qDebug("%s took %.1lf milliseconds %s\n", _message, elapsedmsec, (_alwaysDisplay || (elapsedmsec < 10) ? "" : "WARNING!")); } } else { - qDebug("%s took %lf milliseconds %s\n", _message, elapsedmsec, + qDebug("%s took %.2lf milliseconds %s\n", _message, elapsedmsec, (_alwaysDisplay || (elapsedmsec < 10) ? "" : "WARNING!")); } } } else if (_alwaysDisplay) { - qDebug("%s took %lf milliseconds\n", _message, elapsedmsec); + qDebug("%s took %.2lf milliseconds\n", _message, elapsedmsec); } // if the caller gave us a pointer to store the running total, track it now. if (_runningTotal) { From 2cb701bce6cc751978df97069ebdc17a96c27e9d Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Mon, 25 Nov 2013 17:28:33 -0800 Subject: [PATCH 3/6] Added adjustment for hydra position to user (it matters) --- interface/src/devices/SixenseManager.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/interface/src/devices/SixenseManager.cpp b/interface/src/devices/SixenseManager.cpp index fcb795eaed..dfeab1f309 100644 --- a/interface/src/devices/SixenseManager.cpp +++ b/interface/src/devices/SixenseManager.cpp @@ -58,12 +58,20 @@ void SixenseManager::update() { avatar->setDriveKeys(DOWN, data.trigger); } - // set palm position and normal based on Hydra position/orientation + // Set palm position and normal based on Hydra position/orientation PalmData palm(&hand); palm.setActive(true); - glm::vec3 position(-data.pos[0], data.pos[1], -data.pos[2]); + glm::vec3 position(data.pos[0], data.pos[1], data.pos[2]); + + // Adjust for distance between acquisition 'orb' and the user's torso + // (distance to the right of body center, distance below torso, distance behind torso) + const glm::vec3 SPHERE_TO_TORSO(-250.f, -300.f, -300.f); + position = SPHERE_TO_TORSO + position; palm.setRawPosition(position); glm::quat rotation(data.rot_quat[3], -data.rot_quat[0], data.rot_quat[1], -data.rot_quat[2]); + + // Rotate about controller + rotation = glm::angleAxis(180.0f, 0.f, 1.f, 0.f) * rotation; const glm::vec3 PALM_VECTOR(0.0f, -1.0f, 0.0f); palm.setRawNormal(rotation * PALM_VECTOR); From ec909a6c13a9e07e14d10a5cf8c737fb3892592c Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 26 Nov 2013 10:58:02 -0600 Subject: [PATCH 4/6] add a mutex lock and unlock on Menu instance creation --- interface/src/Menu.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index fd942a77c1..a9c942ca39 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -36,11 +36,18 @@ Menu* Menu::_instance = NULL; Menu* Menu::getInstance() { + static QMutex menuInstanceMutex; + + // lock the menu instance mutex to make sure we don't race and create two menus and crash + menuInstanceMutex.lock(); + if (!_instance) { qDebug("First call to Menu::getInstance() - initing menu.\n"); _instance = new Menu(); } + + menuInstanceMutex.unlock(); return _instance; } From 09ca2a45db29efe9712b38e2e38e7f76d38e12e7 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Tue, 26 Nov 2013 11:25:06 -0800 Subject: [PATCH 5/6] Add local audio monitor option, tweak turning with head --- interface/src/Audio.cpp | 17 ++++---- interface/src/Audio.h | 2 + interface/src/Menu.cpp | 5 ++- interface/src/Menu.h | 3 +- interface/src/avatar/MyAvatar.cpp | 69 +++++++++++++------------------ 5 files changed, 46 insertions(+), 50 deletions(-) diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index d3b23f273a..99bb2786e0 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -27,12 +27,8 @@ #include "Menu.h" #include "Util.h" -// Uncomment the following definition to test audio device latency by copying output to input -//#define TEST_AUDIO_LOOPBACK //#define SHOW_AUDIO_DEBUG -#define VISUALIZE_ECHO_CANCELLATION - static const int PHASE_DELAY_AT_90 = 20; static const float AMPLITUDE_RATIO_AT_90 = 0.5; static const int MIN_FLANGE_EFFECT_THRESHOLD = 600; @@ -84,11 +80,17 @@ inline void Audio::performIO(int16_t* inputLeft, int16_t* outputLeft, int16_t* o memset(outputLeft, 0, PACKET_LENGTH_BYTES_PER_CHANNEL); memset(outputRight, 0, PACKET_LENGTH_BYTES_PER_CHANNEL); - // If Mute button is pressed, clear the input buffer + // If Mute button is pressed, clear the input buffer if (_muted) { memset(inputLeft, 0, PACKET_LENGTH_BYTES_PER_CHANNEL); } + // If local loopback enabled, copy input to output + if (Menu::getInstance()->isOptionChecked(MenuOption::EchoServerAudio)) { + memcpy(outputLeft, inputLeft, PACKET_LENGTH_BYTES_PER_CHANNEL); + memcpy(outputRight, inputLeft, PACKET_LENGTH_BYTES_PER_CHANNEL); + } + // Add Procedural effects to input samples addProceduralSounds(inputLeft, outputLeft, outputRight, BUFFER_LENGTH_SAMPLES_PER_CHANNEL); @@ -120,7 +122,7 @@ inline void Audio::performIO(int16_t* inputLeft, int16_t* outputLeft, int16_t* o // + 12 for 3 floats for position + float for bearing + 1 attenuation byte unsigned char dataPacket[MAX_PACKET_SIZE]; - PACKET_TYPE packetType = Menu::getInstance()->isOptionChecked(MenuOption::EchoAudio) + PACKET_TYPE packetType = Menu::getInstance()->isOptionChecked(MenuOption::EchoServerAudio) ? PACKET_TYPE_MICROPHONE_AUDIO_WITH_ECHO : PACKET_TYPE_MICROPHONE_AUDIO_NO_ECHO; @@ -360,7 +362,8 @@ Audio::Audio(Oscilloscope* scope, int16_t initialJitterBufferSamples) : _collisionSoundDuration(0.0f), _proceduralEffectSample(0), _heartbeatMagnitude(0.0f), - _muted(false) + _muted(false), + _localEcho(false) { outputPortAudioError(Pa_Initialize()); diff --git a/interface/src/Audio.h b/interface/src/Audio.h index ec8ca6989c..347fb0551f 100644 --- a/interface/src/Audio.h +++ b/interface/src/Audio.h @@ -70,6 +70,7 @@ public: // in which case 'true' is returned - otherwise the return value is 'false'. // The results of the analysis are written to the log. bool eventuallyAnalyzePing(); + private: PaStream* _stream; @@ -109,6 +110,7 @@ private: float _heartbeatMagnitude; bool _muted; + bool _localEcho; GLuint _micTextureId; GLuint _muteTextureId; QRect _iconBounds; diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index fd942a77c1..dbf4728b83 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -484,8 +484,9 @@ Menu::Menu() : addCheckableActionToQMenuAndActionHash(renderDebugMenu, MenuOption::CoverageMapV2, Qt::SHIFT | Qt::CTRL | Qt::Key_P); QMenu* audioDebugMenu = developerMenu->addMenu("Audio Debugging Tools"); - addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::EchoAudio); - + addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::EchoServerAudio); + addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::EchoLocalAudio); + QMenu* voxelProtoOptionsMenu = developerMenu->addMenu("Voxel Server Protocol Options"); addCheckableActionToQMenuAndActionHash(voxelProtoOptionsMenu, MenuOption::SendVoxelColors); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index db8b0ed528..aebb8f9858 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -168,7 +168,8 @@ namespace MenuOption { const QString DisplayLeapHands = "Display Leap Hands"; const QString DontRenderVoxels = "Don't call _voxels.render()"; const QString DontCallOpenGLForVoxels = "Don't call glDrawRangeElementsEXT() for Voxels"; - const QString EchoAudio = "Echo Audio"; + const QString EchoServerAudio = "Echo Server Audio"; + const QString EchoLocalAudio = "Echo Local Audio"; const QString ExportVoxels = "Export Voxels"; const QString ExtraDebugging = "Extra Debugging"; const QString DontFadeOnVoxelServerChanges = "Don't Fade In/Out on Voxel Server Changes"; diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 76cf77775e..65670aa4f3 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -381,15 +381,18 @@ void MyAvatar::updateFromGyrosAndOrWebcam(bool turnWithHead) { if (faceshift->isActive()) { estimatedPosition = faceshift->getHeadTranslation(); estimatedRotation = safeEulerAngles(faceshift->getHeadRotation()); - // Rotate the body if the head is turned quickly + // Rotate the body if the head is turned beyond the screen if (turnWithHead) { - glm::vec3 headAngularVelocity = faceshift->getHeadAngularVelocity(); - const float FACESHIFT_YAW_TURN_SENSITIVITY = 0.25f; - const float FACESHIFT_MIN_YAW_TURN = 10.f; - const float FACESHIFT_MAX_YAW_TURN = 30.f; + const float FACESHIFT_YAW_TURN_SENSITIVITY = 0.5f; + const float FACESHIFT_MIN_YAW_TURN = 15.f; + const float FACESHIFT_MAX_YAW_TURN = 50.f; if ( (fabs(estimatedRotation.y) > FACESHIFT_MIN_YAW_TURN) && (fabs(estimatedRotation.y) < FACESHIFT_MAX_YAW_TURN) ) { - _bodyYawDelta += estimatedRotation.y * FACESHIFT_YAW_TURN_SENSITIVITY; + if (estimatedRotation.y > 0.f) { + _bodyYawDelta += (estimatedRotation.y - FACESHIFT_MIN_YAW_TURN) * FACESHIFT_YAW_TURN_SENSITIVITY; + } else { + _bodyYawDelta += (estimatedRotation.y + FACESHIFT_MIN_YAW_TURN) * FACESHIFT_YAW_TURN_SENSITIVITY; + } } } } else if (gyros->isActive()) { @@ -464,43 +467,29 @@ void MyAvatar::updateFromGyrosAndOrWebcam(bool turnWithHead) { glm::quat orientation = _head.getCameraOrientation(); glm::vec3 front = orientation * IDENTITY_FRONT; glm::vec3 right = orientation * IDENTITY_RIGHT; - - const float LEAN_FWD_DEAD_ZONE = 2.f; - const float LEAN_SIDEWAYS_DEAD_ZONE = 2.f; - const float LEAN_FWD_THRUST_SCALE = 1.f; - const float LEAN_SIDEWAYS_THRUST_SCALE = 1.f; - - //printf("%.2f, %.2f\n", _head.getLeanForward(), _head.getLeanSideways()); - - if (fabs(_head.getLeanForward()) > LEAN_FWD_DEAD_ZONE) { - addThrust(front * -_head.getLeanForward() * LEAN_FWD_THRUST_SCALE); - } - if (fabs(_head.getLeanSideways()) > LEAN_SIDEWAYS_DEAD_ZONE) { - addThrust(right * -_head.getLeanSideways() * LEAN_SIDEWAYS_THRUST_SCALE); - } - -/* - const float ANGULAR_DRIVE_SCALE = 0.1f; - const float ANGULAR_DEAD_ZONE = 0.3f; + float leanForward = _head.getLeanForward(); + float leanSideways = _head.getLeanSideways(); - setDriveKeys(FWD, glm::clamp(-_head.getLeanForward() * ANGULAR_DRIVE_SCALE - ANGULAR_DEAD_ZONE, 0.0f, 1.0f)); - setDriveKeys(BACK, glm::clamp(_head.getLeanForward() * ANGULAR_DRIVE_SCALE - ANGULAR_DEAD_ZONE, 0.0f, 1.0f)); - setDriveKeys(LEFT, glm::clamp(_head.getLeanSideways() * ANGULAR_DRIVE_SCALE - ANGULAR_DEAD_ZONE, 0.0f, 1.0f)); - setDriveKeys(RIGHT, glm::clamp(-_head.getLeanSideways() * ANGULAR_DRIVE_SCALE - ANGULAR_DEAD_ZONE, 0.0f, 1.0f)); - */ - - /* - // only consider going up if we're not going in any of the four horizontal directions - if (_driveKeys[FWD] == 0.0f && _driveKeys[BACK] == 0.0f && _driveKeys[LEFT] == 0.0f && _driveKeys[RIGHT] == 0.0f) { - const float LINEAR_DRIVE_SCALE = 5.0f; - const float LINEAR_DEAD_ZONE = 0.95f; - float torsoDelta = glm::length(relativePosition) - TORSO_LENGTH; - setDriveKeys(UP, glm::clamp(torsoDelta * LINEAR_DRIVE_SCALE - LINEAR_DEAD_ZONE, 0.0f, 1.0f)); + // Degrees of 'dead zone' when leaning, and amount of acceleration to apply to lean angle + const float LEAN_FWD_DEAD_ZONE = 15.f; + const float LEAN_SIDEWAYS_DEAD_ZONE = 10.f; + const float LEAN_FWD_THRUST_SCALE = 4.f; + const float LEAN_SIDEWAYS_THRUST_SCALE = 3.f; - } else { - setDriveKeys(UP, 0.0f); + if (fabs(leanForward) > LEAN_FWD_DEAD_ZONE) { + if (leanForward > 0.f) { + addThrust(front * -(leanForward - LEAN_FWD_DEAD_ZONE) * LEAN_FWD_THRUST_SCALE); + } else { + addThrust(front * -(leanForward + LEAN_FWD_DEAD_ZONE) * LEAN_FWD_THRUST_SCALE); + } + } + if (fabs(leanSideways) > LEAN_SIDEWAYS_DEAD_ZONE) { + if (leanSideways > 0.f) { + addThrust(right * -(leanSideways - LEAN_SIDEWAYS_DEAD_ZONE) * LEAN_SIDEWAYS_THRUST_SCALE); + } else { + addThrust(right * -(leanSideways + LEAN_SIDEWAYS_DEAD_ZONE) * LEAN_SIDEWAYS_THRUST_SCALE); + } } - */ } static TextRenderer* textRenderer() { From 534c5105b047af18e67d82ed19184a8facc507ac Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Tue, 26 Nov 2013 11:46:11 -0800 Subject: [PATCH 6/6] echo the right one --- interface/src/Audio.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 99bb2786e0..378d86284a 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -86,7 +86,7 @@ inline void Audio::performIO(int16_t* inputLeft, int16_t* outputLeft, int16_t* o } // If local loopback enabled, copy input to output - if (Menu::getInstance()->isOptionChecked(MenuOption::EchoServerAudio)) { + if (Menu::getInstance()->isOptionChecked(MenuOption::EchoLocalAudio)) { memcpy(outputLeft, inputLeft, PACKET_LENGTH_BYTES_PER_CHANNEL); memcpy(outputRight, inputLeft, PACKET_LENGTH_BYTES_PER_CHANNEL); }