From 09ca2a45db29efe9712b38e2e38e7f76d38e12e7 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Tue, 26 Nov 2013 11:25:06 -0800 Subject: [PATCH] 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() {