From aa47043d5752c16a8685ba48314ac2d2b9909145 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 27 May 2014 11:24:48 -0700 Subject: [PATCH 01/12] Fix WAV file support The previous implementation assumed the file only contained RIFF, WAVE, fmt, and data chunks. It is valid for other chunks to appear, so I updated it to skip any chunks until it finds the "data" chunk. --- libraries/audio/src/Sound.cpp | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/libraries/audio/src/Sound.cpp b/libraries/audio/src/Sound.cpp index 5bd63b7959..9bc78f2303 100644 --- a/libraries/audio/src/Sound.cpp +++ b/libraries/audio/src/Sound.cpp @@ -237,27 +237,30 @@ void Sound::interpretAsWav(const QByteArray& inputAudioByteArray, QByteArray& ou return; } + // Skip any extra data in the WAVE chunk + waveStream.skipRawData(fileHeader.wave.descriptor.size - (sizeof(WAVEHeader) - sizeof(chunk))); + // Read off remaining header information DATAHeader dataHeader; - if (waveStream.readRawData(reinterpret_cast(&dataHeader), sizeof(DATAHeader)) == sizeof(DATAHeader)) { - if (strncmp(dataHeader.descriptor.id, "data", 4) != 0) { - qDebug() << "Invalid wav audio data header."; + while (true) { + // Read chunks until the "data" chunk is found + if (waveStream.readRawData(reinterpret_cast(&dataHeader), sizeof(DATAHeader)) == sizeof(DATAHeader)) { + if (strncmp(dataHeader.descriptor.id, "data", 4) == 0) { + break; + } + waveStream.skipRawData(dataHeader.descriptor.size); + } else { + qDebug() << "Could not read wav audio data header."; return; } - } else { - qDebug() << "Could not read wav audio data header."; - return; - } - - if (qFromLittleEndian(fileHeader.riff.descriptor.size) != qFromLittleEndian(dataHeader.descriptor.size) + 36) { - qDebug() << "Did not read audio file chank headers correctly."; - return; } // Now pull out the data quint32 outputAudioByteArraySize = qFromLittleEndian(dataHeader.descriptor.size); outputAudioByteArray.resize(outputAudioByteArraySize); - waveStream.readRawData(outputAudioByteArray.data(), outputAudioByteArraySize); + if (waveStream.readRawData(outputAudioByteArray.data(), outputAudioByteArraySize) != outputAudioByteArraySize) { + qDebug() << "Error reading WAV file"; + } } else { qDebug() << "Could not read wav audio file header."; From ca6cc86ca124122dcfda7909b0d4cdd9e605fb89 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 27 May 2014 11:35:00 -0700 Subject: [PATCH 02/12] Add playSoundWave.js --- examples/playSoundWave.js | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 examples/playSoundWave.js diff --git a/examples/playSoundWave.js b/examples/playSoundWave.js new file mode 100644 index 0000000000..419fd80cd2 --- /dev/null +++ b/examples/playSoundWave.js @@ -0,0 +1,22 @@ +// +// playSoundWave.js +// examples +// +// Created by Ryan Huffman on 05/27/14. +// Copyright 2014 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 +// + +var soundClip = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Cocktail%20Party%20Snippets/Walken1.wav"); + +function playSound() { + var options = new AudioInjectionOptions(); + var position = MyAvatar.position; + options.position = position; + options.volume = 0.5; + Audio.playSound(soundClip, options); +} + +Script.setInterval(playSound, 10000); From 07544c7b433d82070202f1cf6ba1d079f670926e Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 27 May 2014 12:52:44 -0700 Subject: [PATCH 03/12] removal of unused getNeckRotation() --- interface/src/renderer/Model.cpp | 4 ---- interface/src/renderer/Model.h | 4 ---- 2 files changed, 8 deletions(-) diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 5337e845a1..0cc914b65c 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -613,10 +613,6 @@ bool Model::getNeckPosition(glm::vec3& neckPosition) const { return isActive() && getJointPosition(_geometry->getFBXGeometry().neckJointIndex, neckPosition); } -bool Model::getNeckRotation(glm::quat& neckRotation) const { - return isActive() && getJointRotation(_geometry->getFBXGeometry().neckJointIndex, neckRotation); -} - bool Model::getNeckParentRotation(glm::quat& neckParentRotation) const { if (!isActive()) { return false; diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index 5b1f6402d3..26e80dfd52 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -135,10 +135,6 @@ public: /// \return whether or not the neck was found bool getNeckPosition(glm::vec3& neckPosition) const; - /// Returns the rotation of the neck joint. - /// \return whether or not the neck was found - bool getNeckRotation(glm::quat& neckRotation) const; - /// Returns the rotation of the neck joint's parent. /// \return whether or not the neck was found bool getNeckParentRotation(glm::quat& neckRotation) const; From 2b54d627c0662ce0a1a0ba91386e95c8f02f54e5 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 27 May 2014 14:25:27 -0700 Subject: [PATCH 04/12] Try rounding to nearest texel unit to reduce shimmer. --- interface/src/Application.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 5b43159122..32fa50e710 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2291,6 +2291,11 @@ void Application::updateShadowMap() { radius = qMax(radius, glm::distance(points[i], center)); } center = inverseRotation * center; + + // to reduce texture "shimmer," move in texel increments + float texelSize = (2.0f * radius) / fbo->width(); + center = glm::round(center / texelSize) * texelSize; + glm::vec3 minima(center.x - radius, center.y - radius, center.z - radius); glm::vec3 maxima(center.x + radius, center.y + radius, center.z + radius); From f7b8c4f0a082717560ad58b59cdf4d10033ad004 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 27 May 2014 14:50:17 -0700 Subject: [PATCH 05/12] remove unused Head::_gravity data memeber --- interface/src/avatar/Head.cpp | 1 - interface/src/avatar/Head.h | 2 -- interface/src/avatar/MyAvatar.cpp | 1 - 3 files changed, 4 deletions(-) diff --git a/interface/src/avatar/Head.cpp b/interface/src/avatar/Head.cpp index 2d0599b31f..ffb33b2619 100644 --- a/interface/src/avatar/Head.cpp +++ b/interface/src/avatar/Head.cpp @@ -31,7 +31,6 @@ Head::Head(Avatar* owningAvatar) : _rightEyePosition(0.0f, 0.0f, 0.0f), _eyePosition(0.0f, 0.0f, 0.0f), _scale(1.0f), - _gravity(0.0f, -1.0f, 0.0f), _lastLoudness(0.0f), _audioAttack(0.0f), _angularVelocity(0,0,0), diff --git a/interface/src/avatar/Head.h b/interface/src/avatar/Head.h index 8c58b73ebd..cd7abeb9de 100644 --- a/interface/src/avatar/Head.h +++ b/interface/src/avatar/Head.h @@ -45,7 +45,6 @@ public: void render(float alpha, Model::RenderMode mode); void setScale(float scale); void setPosition(glm::vec3 position) { _position = position; } - void setGravity(glm::vec3 gravity) { _gravity = gravity; } void setAverageLoudness(float averageLoudness) { _averageLoudness = averageLoudness; } void setReturnToCenter (bool returnHeadToCenter) { _returnHeadToCenter = returnHeadToCenter; } void setRenderLookatVectors(bool onOff) { _renderLookatVectors = onOff; } @@ -118,7 +117,6 @@ private: glm::vec3 _rightEyePosition; glm::vec3 _eyePosition; float _scale; - glm::vec3 _gravity; float _lastLoudness; float _audioAttack; glm::vec3 _angularVelocity; diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index a598c55aaa..fecbcd7023 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -378,7 +378,6 @@ void MyAvatar::setLocalGravity(glm::vec3 gravity) { void MyAvatar::setGravity(const glm::vec3& gravity) { _gravity = gravity; - getHead()->setGravity(_gravity); // use the gravity to determine the new world up direction, if possible float gravityLength = glm::length(gravity); From 6efa417742b3d07aaee90c5e4f71cb383de6dbd2 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 27 May 2014 15:06:50 -0700 Subject: [PATCH 06/12] move hand/arm stuff from Model to SkeletonModel --- interface/src/avatar/Hand.cpp | 2 +- interface/src/avatar/SkeletonModel.cpp | 40 ++++++++++++++++++++++ interface/src/avatar/SkeletonModel.h | 46 ++++++++++++++++++++++++++ interface/src/renderer/Model.cpp | 40 ---------------------- interface/src/renderer/Model.h | 46 -------------------------- 5 files changed, 87 insertions(+), 87 deletions(-) diff --git a/interface/src/avatar/Hand.cpp b/interface/src/avatar/Hand.cpp index 5f168c4f45..3aff984893 100644 --- a/interface/src/avatar/Hand.cpp +++ b/interface/src/avatar/Hand.cpp @@ -103,7 +103,7 @@ void Hand::collideAgainstOurself() { getLeftRightPalmIndices(leftPalmIndex, rightPalmIndex); float scaledPalmRadius = PALM_COLLISION_RADIUS * _owningAvatar->getScale(); - const Model& skeletonModel = _owningAvatar->getSkeletonModel(); + const SkeletonModel& skeletonModel = _owningAvatar->getSkeletonModel(); for (int i = 0; i < int(getNumPalms()); i++) { PalmData& palm = getPalms()[i]; if (!palm.isActive()) { diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index 429ab1cf30..9fe52f81ce 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -347,4 +347,44 @@ void SkeletonModel::setHandPosition(int jointIndex, const glm::vec3& position, c setJointRotation(jointIndex, rotation, true, PALM_PRIORITY); } + +bool SkeletonModel::getLeftHandPosition(glm::vec3& position) const { + return getJointPosition(getLeftHandJointIndex(), position); +} + +bool SkeletonModel::getLeftHandRotation(glm::quat& rotation) const { + return getJointRotation(getLeftHandJointIndex(), rotation); +} + +bool SkeletonModel::getRightHandPosition(glm::vec3& position) const { + return getJointPosition(getRightHandJointIndex(), position); +} + +bool SkeletonModel::getRightHandRotation(glm::quat& rotation) const { + return getJointRotation(getRightHandJointIndex(), rotation); +} + +bool SkeletonModel::restoreLeftHandPosition(float percent, float priority) { + return restoreJointPosition(getLeftHandJointIndex(), percent, priority); +} + +bool SkeletonModel::getLeftShoulderPosition(glm::vec3& position) const { + return getJointPosition(getLastFreeJointIndex(getLeftHandJointIndex()), position); +} + +float SkeletonModel::getLeftArmLength() const { + return getLimbLength(getLeftHandJointIndex()); +} + +bool SkeletonModel::restoreRightHandPosition(float percent, float priority) { + return restoreJointPosition(getRightHandJointIndex(), percent, priority); +} + +bool SkeletonModel::getRightShoulderPosition(glm::vec3& position) const { + return getJointPosition(getLastFreeJointIndex(getRightHandJointIndex()), position); +} + +float SkeletonModel::getRightArmLength() const { + return getLimbLength(getRightHandJointIndex()); +} diff --git a/interface/src/avatar/SkeletonModel.h b/interface/src/avatar/SkeletonModel.h index 77e6ea33d4..6a46b3b88e 100644 --- a/interface/src/avatar/SkeletonModel.h +++ b/interface/src/avatar/SkeletonModel.h @@ -34,7 +34,53 @@ public: void getBodyShapes(QVector& shapes) const; void renderIKConstraints(); + + /// Returns the index of the left hand joint, or -1 if not found. + int getLeftHandJointIndex() const { return isActive() ? _geometry->getFBXGeometry().leftHandJointIndex : -1; } + + /// Returns the index of the right hand joint, or -1 if not found. + int getRightHandJointIndex() const { return isActive() ? _geometry->getFBXGeometry().rightHandJointIndex : -1; } + /// Retrieve the position of the left hand + /// \return true whether or not the position was found + bool getLeftHandPosition(glm::vec3& position) const; + + /// Retrieve the rotation of the left hand + /// \return true whether or not the rotation was found + bool getLeftHandRotation(glm::quat& rotation) const; + + /// Retrieve the position of the right hand + /// \return true whether or not the position was found + bool getRightHandPosition(glm::vec3& position) const; + + /// Retrieve the rotation of the right hand + /// \return true whether or not the rotation was found + bool getRightHandRotation(glm::quat& rotation) const; + + /// Restores some percentage of the default position of the left hand. + /// \param percent the percentage of the default position to restore + /// \return whether or not the left hand joint was found + bool restoreLeftHandPosition(float percent = 1.0f, float priority = 1.0f); + + /// Gets the position of the left shoulder. + /// \return whether or not the left shoulder joint was found + bool getLeftShoulderPosition(glm::vec3& position) const; + + /// Returns the extended length from the left hand to its last free ancestor. + float getLeftArmLength() const; + + /// Restores some percentage of the default position of the right hand. + /// \param percent the percentage of the default position to restore + /// \return whether or not the right hand joint was found + bool restoreRightHandPosition(float percent = 1.0f, float priority = 1.0f); + + /// Gets the position of the right shoulder. + /// \return whether or not the right shoulder joint was found + bool getRightShoulderPosition(glm::vec3& position) const; + + /// Returns the extended length from the right hand to its first free ancestor. + float getRightArmLength() const; + protected: void applyHandPosition(int jointIndex, const glm::vec3& position); diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index d14e7ce44f..192bacdce9 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -640,46 +640,6 @@ bool Model::getEyePositions(glm::vec3& firstEyePosition, glm::vec3& secondEyePos return getJointPosition(geometry.leftEyeJointIndex, firstEyePosition) && getJointPosition(geometry.rightEyeJointIndex, secondEyePosition); } - -bool Model::getLeftHandPosition(glm::vec3& position) const { - return getJointPosition(getLeftHandJointIndex(), position); -} - -bool Model::getLeftHandRotation(glm::quat& rotation) const { - return getJointRotation(getLeftHandJointIndex(), rotation); -} - -bool Model::getRightHandPosition(glm::vec3& position) const { - return getJointPosition(getRightHandJointIndex(), position); -} - -bool Model::getRightHandRotation(glm::quat& rotation) const { - return getJointRotation(getRightHandJointIndex(), rotation); -} - -bool Model::restoreLeftHandPosition(float percent, float priority) { - return restoreJointPosition(getLeftHandJointIndex(), percent, priority); -} - -bool Model::getLeftShoulderPosition(glm::vec3& position) const { - return getJointPosition(getLastFreeJointIndex(getLeftHandJointIndex()), position); -} - -float Model::getLeftArmLength() const { - return getLimbLength(getLeftHandJointIndex()); -} - -bool Model::restoreRightHandPosition(float percent, float priority) { - return restoreJointPosition(getRightHandJointIndex(), percent, priority); -} - -bool Model::getRightShoulderPosition(glm::vec3& position) const { - return getJointPosition(getLastFreeJointIndex(getRightHandJointIndex()), position); -} - -float Model::getRightArmLength() const { - return getLimbLength(getRightHandJointIndex()); -} void Model::setURL(const QUrl& url, const QUrl& fallback, bool retainCurrent, bool delayLoad) { // don't recreate the geometry if it's the same URL diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index 5d224c48f8..763cbdb577 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -115,12 +115,6 @@ public: /// Sets the joint state at the specified index. void setJointState(int index, bool valid, const glm::quat& rotation = glm::quat(), float priority = 1.0f); - /// Returns the index of the left hand joint, or -1 if not found. - int getLeftHandJointIndex() const { return isActive() ? _geometry->getFBXGeometry().leftHandJointIndex : -1; } - - /// Returns the index of the right hand joint, or -1 if not found. - int getRightHandJointIndex() const { return isActive() ? _geometry->getFBXGeometry().rightHandJointIndex : -1; } - /// Returns the index of the parent of the indexed joint, or -1 if not found. int getParentJointIndex(int jointIndex) const; @@ -143,46 +137,6 @@ public: /// \return whether or not both eye meshes were found bool getEyePositions(glm::vec3& firstEyePosition, glm::vec3& secondEyePosition) const; - /// Retrieve the position of the left hand - /// \return true whether or not the position was found - bool getLeftHandPosition(glm::vec3& position) const; - - /// Retrieve the rotation of the left hand - /// \return true whether or not the rotation was found - bool getLeftHandRotation(glm::quat& rotation) const; - - /// Retrieve the position of the right hand - /// \return true whether or not the position was found - bool getRightHandPosition(glm::vec3& position) const; - - /// Retrieve the rotation of the right hand - /// \return true whether or not the rotation was found - bool getRightHandRotation(glm::quat& rotation) const; - - /// Restores some percentage of the default position of the left hand. - /// \param percent the percentage of the default position to restore - /// \return whether or not the left hand joint was found - bool restoreLeftHandPosition(float percent = 1.0f, float priority = 1.0f); - - /// Gets the position of the left shoulder. - /// \return whether or not the left shoulder joint was found - bool getLeftShoulderPosition(glm::vec3& position) const; - - /// Returns the extended length from the left hand to its last free ancestor. - float getLeftArmLength() const; - - /// Restores some percentage of the default position of the right hand. - /// \param percent the percentage of the default position to restore - /// \return whether or not the right hand joint was found - bool restoreRightHandPosition(float percent = 1.0f, float priority = 1.0f); - - /// Gets the position of the right shoulder. - /// \return whether or not the right shoulder joint was found - bool getRightShoulderPosition(glm::vec3& position) const; - - /// Returns the extended length from the right hand to its first free ancestor. - float getRightArmLength() const; - bool getJointPosition(int jointIndex, glm::vec3& position) const; bool getJointRotation(int jointIndex, glm::quat& rotation, bool fromBind = false) const; From ae3b792a352d2e8755efcf8b3fad2d6c802b5b49 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 27 May 2014 15:28:41 -0700 Subject: [PATCH 07/12] move face/head code from Model into SkeletonModel --- interface/src/avatar/FaceModel.cpp | 9 +++++ interface/src/avatar/FaceModel.h | 4 +++ interface/src/avatar/SkeletonModel.cpp | 45 ++++++++++++++++++++++- interface/src/avatar/SkeletonModel.h | 22 ++++++++++-- interface/src/renderer/Model.cpp | 49 -------------------------- interface/src/renderer/Model.h | 20 ----------- 6 files changed, 76 insertions(+), 73 deletions(-) diff --git a/interface/src/avatar/FaceModel.cpp b/interface/src/avatar/FaceModel.cpp index 90e596bde5..eaa9875641 100644 --- a/interface/src/avatar/FaceModel.cpp +++ b/interface/src/avatar/FaceModel.cpp @@ -69,3 +69,12 @@ void FaceModel::maybeUpdateEyeRotation(const JointState& parentState, const FBXJ state.rotation = glm::angleAxis(glm::clamp(glm::angle(between), -MAX_ANGLE, MAX_ANGLE), glm::axis(between)) * joint.rotation; } + +bool FaceModel::getEyePositions(glm::vec3& firstEyePosition, glm::vec3& secondEyePosition) const { + if (!isActive()) { + return false; + } + const FBXGeometry& geometry = _geometry->getFBXGeometry(); + return getJointPosition(geometry.leftEyeJointIndex, firstEyePosition) && + getJointPosition(geometry.rightEyeJointIndex, secondEyePosition); +} diff --git a/interface/src/avatar/FaceModel.h b/interface/src/avatar/FaceModel.h index 0b7fea8ec4..c3462f42ac 100644 --- a/interface/src/avatar/FaceModel.h +++ b/interface/src/avatar/FaceModel.h @@ -29,6 +29,10 @@ public: virtual void maybeUpdateNeckRotation(const JointState& parentState, const FBXJoint& joint, JointState& state); virtual void maybeUpdateEyeRotation(const JointState& parentState, const FBXJoint& joint, JointState& state); + /// Retrieve the positions of up to two eye meshes. + /// \return whether or not both eye meshes were found + bool getEyePositions(glm::vec3& firstEyePosition, glm::vec3& secondEyePosition) const; + private: Head* _owningHead; diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index 9fe52f81ce..9867f03f4c 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -198,10 +198,25 @@ void SkeletonModel::applyPalmData(int jointIndex, PalmData& palm) { } void SkeletonModel::updateJointState(int index) { + JointState& state = _jointStates[index]; + const FBXGeometry& geometry = _geometry->getFBXGeometry(); + const FBXJoint& joint = geometry.joints.at(index); + if (joint.parentIndex == -1) { + const JointState& parentState = _jointStates.at(joint.parentIndex); + if (index == geometry.leanJointIndex) { + maybeUpdateLeanRotation(parentState, joint, state); + + } else if (index == geometry.neckJointIndex) { + maybeUpdateNeckRotation(parentState, joint, state); + + } else if (index == geometry.leftEyeJointIndex || index == geometry.rightEyeJointIndex) { + maybeUpdateEyeRotation(parentState, joint, state); + } + } + Model::updateJointState(index); if (index == _geometry->getFBXGeometry().rootJointIndex) { - JointState& state = _jointStates[index]; state.transform[3][0] = 0.0f; state.transform[3][1] = 0.0f; state.transform[3][2] = 0.0f; @@ -388,3 +403,31 @@ float SkeletonModel::getRightArmLength() const { return getLimbLength(getRightHandJointIndex()); } +bool SkeletonModel::getHeadPosition(glm::vec3& headPosition) const { + return isActive() && getJointPosition(_geometry->getFBXGeometry().headJointIndex, headPosition); +} + +bool SkeletonModel::getNeckPosition(glm::vec3& neckPosition) const { + return isActive() && getJointPosition(_geometry->getFBXGeometry().neckJointIndex, neckPosition); +} + +bool SkeletonModel::getNeckParentRotation(glm::quat& neckParentRotation) const { + if (!isActive()) { + return false; + } + const FBXGeometry& geometry = _geometry->getFBXGeometry(); + if (geometry.neckJointIndex == -1) { + return false; + } + return getJointRotation(geometry.joints.at(geometry.neckJointIndex).parentIndex, neckParentRotation); +} + +bool SkeletonModel::getEyePositions(glm::vec3& firstEyePosition, glm::vec3& secondEyePosition) const { + if (!isActive()) { + return false; + } + const FBXGeometry& geometry = _geometry->getFBXGeometry(); + return getJointPosition(geometry.leftEyeJointIndex, firstEyePosition) && + getJointPosition(geometry.rightEyeJointIndex, secondEyePosition); +} + diff --git a/interface/src/avatar/SkeletonModel.h b/interface/src/avatar/SkeletonModel.h index 6a46b3b88e..60e925b239 100644 --- a/interface/src/avatar/SkeletonModel.h +++ b/interface/src/avatar/SkeletonModel.h @@ -80,6 +80,22 @@ public: /// Returns the extended length from the right hand to its first free ancestor. float getRightArmLength() const; + + /// Returns the position of the head joint. + /// \return whether or not the head was found + bool getHeadPosition(glm::vec3& headPosition) const; + + /// Returns the position of the neck joint. + /// \return whether or not the neck was found + bool getNeckPosition(glm::vec3& neckPosition) const; + + /// Returns the rotation of the neck joint's parent. + /// \return whether or not the neck was found + bool getNeckParentRotation(glm::quat& neckRotation) const; + + /// Retrieve the positions of up to two eye meshes. + /// \return whether or not both eye meshes were found + bool getEyePositions(glm::vec3& firstEyePosition, glm::vec3& secondEyePosition) const; protected: @@ -90,9 +106,9 @@ protected: /// Updates the state of the joint at the specified index. virtual void updateJointState(int index); - virtual void maybeUpdateLeanRotation(const JointState& parentState, const FBXJoint& joint, JointState& state); - virtual void maybeUpdateNeckRotation(const JointState& parentState, const FBXJoint& joint, JointState& state); - virtual void maybeUpdateEyeRotation(const JointState& parentState, const FBXJoint& joint, JointState& state); + void maybeUpdateLeanRotation(const JointState& parentState, const FBXJoint& joint, JointState& state); + void maybeUpdateNeckRotation(const JointState& parentState, const FBXJoint& joint, JointState& state); + void maybeUpdateEyeRotation(const JointState& parentState, const FBXJoint& joint, JointState& state); private: diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 192bacdce9..5a93dbcf25 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -613,34 +613,6 @@ int Model::getLastFreeJointIndex(int jointIndex) const { return (isActive() && jointIndex != -1) ? _geometry->getFBXGeometry().joints.at(jointIndex).freeLineage.last() : -1; } -bool Model::getHeadPosition(glm::vec3& headPosition) const { - return isActive() && getJointPosition(_geometry->getFBXGeometry().headJointIndex, headPosition); -} - -bool Model::getNeckPosition(glm::vec3& neckPosition) const { - return isActive() && getJointPosition(_geometry->getFBXGeometry().neckJointIndex, neckPosition); -} - -bool Model::getNeckParentRotation(glm::quat& neckParentRotation) const { - if (!isActive()) { - return false; - } - const FBXGeometry& geometry = _geometry->getFBXGeometry(); - if (geometry.neckJointIndex == -1) { - return false; - } - return getJointRotation(geometry.joints.at(geometry.neckJointIndex).parentIndex, neckParentRotation); -} - -bool Model::getEyePositions(glm::vec3& firstEyePosition, glm::vec3& secondEyePosition) const { - if (!isActive()) { - return false; - } - const FBXGeometry& geometry = _geometry->getFBXGeometry(); - return getJointPosition(geometry.leftEyeJointIndex, firstEyePosition) && - getJointPosition(geometry.rightEyeJointIndex, secondEyePosition); -} - void Model::setURL(const QUrl& url, const QUrl& fallback, bool retainCurrent, bool delayLoad) { // don't recreate the geometry if it's the same URL if (_url == url) { @@ -1166,15 +1138,6 @@ void Model::updateJointState(int index) { state.combinedRotation = _rotation * combinedRotation; } else { const JointState& parentState = _jointStates.at(joint.parentIndex); - if (index == geometry.leanJointIndex) { - maybeUpdateLeanRotation(parentState, joint, state); - - } else if (index == geometry.neckJointIndex) { - maybeUpdateNeckRotation(parentState, joint, state); - - } else if (index == geometry.leftEyeJointIndex || index == geometry.rightEyeJointIndex) { - maybeUpdateEyeRotation(parentState, joint, state); - } glm::quat combinedRotation = joint.preRotation * state.rotation * joint.postRotation; state.transform = parentState.transform * glm::translate(state.translation) * joint.preTransform * glm::mat4_cast(combinedRotation) * joint.postTransform; @@ -1182,18 +1145,6 @@ void Model::updateJointState(int index) { } } -void Model::maybeUpdateLeanRotation(const JointState& parentState, const FBXJoint& joint, JointState& state) { - // nothing by default -} - -void Model::maybeUpdateNeckRotation(const JointState& parentState, const FBXJoint& joint, JointState& state) { - // nothing by default -} - -void Model::maybeUpdateEyeRotation(const JointState& parentState, const FBXJoint& joint, JointState& state) { - // nothing by default -} - bool Model::setJointPosition(int jointIndex, const glm::vec3& translation, const glm::quat& rotation, bool useRotation, int lastFreeIndex, bool allIntermediatesFree, const glm::vec3& alignment, float priority) { if (jointIndex == -1 || _jointStates.isEmpty()) { diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index 763cbdb577..a4e45287dd 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -121,22 +121,6 @@ public: /// Returns the index of the last free ancestor of the indexed joint, or -1 if not found. int getLastFreeJointIndex(int jointIndex) const; - /// Returns the position of the head joint. - /// \return whether or not the head was found - bool getHeadPosition(glm::vec3& headPosition) const; - - /// Returns the position of the neck joint. - /// \return whether or not the neck was found - bool getNeckPosition(glm::vec3& neckPosition) const; - - /// Returns the rotation of the neck joint's parent. - /// \return whether or not the neck was found - bool getNeckParentRotation(glm::quat& neckRotation) const; - - /// Retrieve the positions of up to two eye meshes. - /// \return whether or not both eye meshes were found - bool getEyePositions(glm::vec3& firstEyePosition, glm::vec3& secondEyePosition) const; - bool getJointPosition(int jointIndex, glm::vec3& position) const; bool getJointRotation(int jointIndex, glm::quat& rotation, bool fromBind = false) const; @@ -234,10 +218,6 @@ protected: /// Updates the state of the joint at the specified index. virtual void updateJointState(int index); - virtual void maybeUpdateLeanRotation(const JointState& parentState, const FBXJoint& joint, JointState& state); - virtual void maybeUpdateNeckRotation(const JointState& parentState, const FBXJoint& joint, JointState& state); - virtual void maybeUpdateEyeRotation(const JointState& parentState, const FBXJoint& joint, JointState& state); - bool setJointPosition(int jointIndex, const glm::vec3& translation, const glm::quat& rotation = glm::quat(), bool useRotation = false, int lastFreeIndex = -1, bool allIntermediatesFree = false, const glm::vec3& alignment = glm::vec3(0.0f, -1.0f, 0.0f), float priority = 1.0f); From 9f72d6ca3f6890734d37287f509c25ca053118ad Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 27 May 2014 15:53:20 -0700 Subject: [PATCH 08/12] fix bug -- negate logic around invalid joint index --- interface/src/avatar/SkeletonModel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index 9867f03f4c..7333bfc395 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -201,7 +201,7 @@ void SkeletonModel::updateJointState(int index) { JointState& state = _jointStates[index]; const FBXGeometry& geometry = _geometry->getFBXGeometry(); const FBXJoint& joint = geometry.joints.at(index); - if (joint.parentIndex == -1) { + if (joint.parentIndex != -1) { const JointState& parentState = _jointStates.at(joint.parentIndex); if (index == geometry.leanJointIndex) { maybeUpdateLeanRotation(parentState, joint, state); From d1a8c18d10621dd29df8f21cb7bf9bb9e860d776 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 27 May 2014 16:32:29 -0700 Subject: [PATCH 09/12] simplified hand index constants --- interface/src/devices/PrioVR.cpp | 8 ++++---- libraries/avatars/src/HandData.cpp | 4 ++-- libraries/avatars/src/HandData.h | 8 ++------ 3 files changed, 8 insertions(+), 12 deletions(-) diff --git a/interface/src/devices/PrioVR.cpp b/interface/src/devices/PrioVR.cpp index deba4f82a5..3e19f1800e 100644 --- a/interface/src/devices/PrioVR.cpp +++ b/interface/src/devices/PrioVR.cpp @@ -63,7 +63,7 @@ static void setPalm(float deltaTime, int index) { if (!Application::getInstance()->getJoystickManager()->getJoystickStates().isEmpty()) { const JoystickState& state = Application::getInstance()->getJoystickManager()->getJoystickStates().at(0); if (state.axes.size() >= 4 && state.buttons.size() >= 4) { - if (index == SIXENSE_CONTROLLER_ID_LEFT_HAND) { + if (index == LEFT_HAND_INDEX) { palm->setControllerButtons(state.buttons.at(1) ? BUTTON_FWD : 0); palm->setTrigger(state.buttons.at(0) ? 1.0f : 0.0f); palm->setJoystick(state.axes.at(0), -state.axes.at(1)); @@ -82,7 +82,7 @@ static void setPalm(float deltaTime, int index) { Model* skeletonModel = &Application::getInstance()->getAvatar()->getSkeletonModel(); int jointIndex; glm::quat inverseRotation = glm::inverse(Application::getInstance()->getAvatar()->getOrientation()); - if (index == SIXENSE_CONTROLLER_ID_LEFT_HAND) { + if (index == LEFT_HAND_INDEX) { jointIndex = skeletonModel->getLeftHandJointIndex(); skeletonModel->getJointRotation(jointIndex, rotation, true); rotation = inverseRotation * rotation * glm::quat(glm::vec3(0.0f, PI_OVER_TWO, 0.0f)); @@ -180,8 +180,8 @@ void PrioVR::update(float deltaTime) { } // convert the joysticks into palm data - setPalm(deltaTime, SIXENSE_CONTROLLER_ID_LEFT_HAND); - setPalm(deltaTime, SIXENSE_CONTROLLER_ID_RIGHT_HAND); + setPalm(deltaTime, LEFT_HAND_INDEX); + setPalm(deltaTime, RIGHT_HAND_INDEX); #endif } diff --git a/libraries/avatars/src/HandData.cpp b/libraries/avatars/src/HandData.cpp index c0553a2b57..e6ef10ed3e 100644 --- a/libraries/avatars/src/HandData.cpp +++ b/libraries/avatars/src/HandData.cpp @@ -53,10 +53,10 @@ void HandData::getLeftRightPalmIndices(int& leftPalmIndex, int& rightPalmIndex) for (size_t i = 0; i < _palms.size(); i++) { const PalmData& palm = _palms[i]; if (palm.isActive()) { - if (palm.getSixenseID() == SIXENSE_CONTROLLER_ID_LEFT_HAND) { + if (palm.getSixenseID() == LEFT_HAND_INDEX) { leftPalmIndex = i; } - if (palm.getSixenseID() == SIXENSE_CONTROLLER_ID_RIGHT_HAND) { + if (palm.getSixenseID() == RIGHT_HAND_INDEX) { rightPalmIndex = i; } } diff --git a/libraries/avatars/src/HandData.h b/libraries/avatars/src/HandData.h index 7e8622f518..404d00b0f3 100755 --- a/libraries/avatars/src/HandData.h +++ b/libraries/avatars/src/HandData.h @@ -23,16 +23,12 @@ class AvatarData; class PalmData; +const int LEFT_HAND_INDEX = 0; +const int RIGHT_HAND_INDEX = 1; const int NUM_HANDS = 2; -const int NUM_FINGERS_PER_HAND = 5; -const int NUM_FINGERS = NUM_HANDS * NUM_FINGERS_PER_HAND; -const int LEAPID_INVALID = -1; const int SIXENSEID_INVALID = -1; -const int SIXENSE_CONTROLLER_ID_LEFT_HAND = 0; -const int SIXENSE_CONTROLLER_ID_RIGHT_HAND = 1; - class HandData { public: HandData(AvatarData* owningAvatar); From 7c124176533853fdd6be4474a78ff63bd00e61c2 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 27 May 2014 17:26:19 -0700 Subject: [PATCH 10/12] Use multisampling on the shadow maps for the voxels, too. --- interface/resources/shaders/shadow_map.frag | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/interface/resources/shaders/shadow_map.frag b/interface/resources/shaders/shadow_map.frag index 70c459ecf8..fb3474d9ef 100644 --- a/interface/resources/shaders/shadow_map.frag +++ b/interface/resources/shaders/shadow_map.frag @@ -13,8 +13,15 @@ uniform sampler2DShadow shadowMap; +// the inverse of the size of the shadow map +const float shadowScale = 1.0 / 2048.0; + varying vec4 shadowColor; void main(void) { - gl_FragColor = mix(shadowColor, gl_Color, shadow2D(shadowMap, gl_TexCoord[0].stp)); + gl_FragColor = mix(shadowColor, gl_Color, 0.25 * + (shadow2D(shadowMap, gl_TexCoord[0].stp + vec3(-shadowScale, -shadowScale, 0.0)).r + + shadow2D(shadowMap, gl_TexCoord[0].stp + vec3(-shadowScale, shadowScale, 0.0)).r + + shadow2D(shadowMap, gl_TexCoord[0].stp + vec3(shadowScale, -shadowScale, 0.0)).r + + shadow2D(shadowMap, gl_TexCoord[0].stp + vec3(shadowScale, shadowScale, 0.0)).r)); } From 62eeeaa1c61a0a43b9013442d12a49d6e9b700aa Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 27 May 2014 18:12:15 -0700 Subject: [PATCH 11/12] Fix for Windows build failure. --- interface/src/Application.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 32fa50e710..37aa23f317 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2294,7 +2294,8 @@ void Application::updateShadowMap() { // to reduce texture "shimmer," move in texel increments float texelSize = (2.0f * radius) / fbo->width(); - center = glm::round(center / texelSize) * texelSize; + center = glm::vec3(roundf(center.x / texelSize) * texelSize, roundf(center.y / texelSize) * texelSize, + roundf(center.z / texelSize) * texelSize); glm::vec3 minima(center.x - radius, center.y - radius, center.z - radius); glm::vec3 maxima(center.x + radius, center.y + radius, center.z + radius); From 619db8ee934dca1dcddf5f6fe53f34d20e77fbef Mon Sep 17 00:00:00 2001 From: matsukaze Date: Tue, 27 May 2014 23:24:28 -0400 Subject: [PATCH 12/12] Job #19694 - Add option for larger number of frames to the audio scope display --- interface/src/Audio.cpp | 152 +++++++++++++++++++++++++++++++--------- interface/src/Audio.h | 27 ++++--- interface/src/Menu.cpp | 30 +++++++- interface/src/Menu.h | 4 ++ 4 files changed, 171 insertions(+), 42 deletions(-) diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index c5d6ba23cf..50ab720450 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -97,9 +97,11 @@ Audio::Audio(int16_t initialJitterBufferSamples, QObject* parent) : _scopeEnabledPause(false), _scopeInputOffset(0), _scopeOutputOffset(0), - _scopeInput(SAMPLES_PER_SCOPE_WIDTH * sizeof(int16_t), 0), - _scopeOutputLeft(SAMPLES_PER_SCOPE_WIDTH * sizeof(int16_t), 0), - _scopeOutputRight(SAMPLES_PER_SCOPE_WIDTH * sizeof(int16_t), 0) + _framesPerScope(DEFAULT_FRAMES_PER_SCOPE), + _samplesPerScope(NETWORK_SAMPLES_PER_FRAME * _framesPerScope), + _scopeInput(0), + _scopeOutputLeft(0), + _scopeOutputRight(0) { // clear the array of locally injected samples memset(_localProceduralSamples, 0, NETWORK_BUFFER_LENGTH_BYTES_PER_CHANNEL); @@ -592,7 +594,7 @@ void Audio::handleAudioInput() { unsigned int monoAudioChannel = 0; addBufferToScope(_scopeInput, _scopeInputOffset, monoAudioSamples, monoAudioChannel, numMonoAudioChannels); _scopeInputOffset += NETWORK_SAMPLES_PER_FRAME; - _scopeInputOffset %= SAMPLES_PER_SCOPE_WIDTH; + _scopeInputOffset %= _samplesPerScope; } NodeList* nodeList = NodeList::getInstance(); @@ -849,7 +851,7 @@ void Audio::processReceivedAudio(const QByteArray& audioByteArray) { samples, audioChannel, numAudioChannels); _scopeOutputOffset += NETWORK_SAMPLES_PER_FRAME; - _scopeOutputOffset %= SAMPLES_PER_SCOPE_WIDTH; + _scopeOutputOffset %= _samplesPerScope; samples += NETWORK_SAMPLES_PER_FRAME * numAudioChannels; } } @@ -1060,25 +1062,73 @@ void Audio::renderToolBox(int x, int y, bool boxed) { glDisable(GL_TEXTURE_2D); } +void Audio::toggleScope() { + _scopeEnabled = !_scopeEnabled; + if (_scopeEnabled) { + _scopeInputOffset = 0; + _scopeOutputOffset = 0; + allocateScope(); + } else { + freeScope(); + } +} + void Audio::toggleScopePause() { _scopeEnabledPause = !_scopeEnabledPause; } -void Audio::toggleScope() { - _scopeEnabled = !_scopeEnabled; - if (_scopeEnabled) { - static const int width = SAMPLES_PER_SCOPE_WIDTH; - _scopeInputOffset = 0; - _scopeOutputOffset = 0; - memset(_scopeInput.data(), 0, width * sizeof(int16_t)); - memset(_scopeOutputLeft.data(), 0, width * sizeof(int16_t)); - memset(_scopeOutputRight.data(), 0, width * sizeof(int16_t)); - _scopeEnabledPause = false; +void Audio::selectAudioScopeFiveFrames() { + if (Menu::getInstance()->isOptionChecked(MenuOption::AudioScopeFiveFrames)) { + reallocateScope(5); + } +} + +void Audio::selectAudioScopeTwentyFrames() { + if (Menu::getInstance()->isOptionChecked(MenuOption::AudioScopeTwentyFrames)) { + reallocateScope(20); + } +} + +void Audio::selectAudioScopeFiftyFrames() { + if (Menu::getInstance()->isOptionChecked(MenuOption::AudioScopeFiftyFrames)) { + reallocateScope(50); + } +} + +void Audio::allocateScope() { + int num = _samplesPerScope * sizeof(int16_t); + _scopeInput = new QByteArray(num, 0); + _scopeOutputLeft = new QByteArray(num, 0); + _scopeOutputRight = new QByteArray(num, 0); +} + +void Audio::reallocateScope(int frames) { + if (_framesPerScope != frames) { + _framesPerScope = frames; + _samplesPerScope = NETWORK_SAMPLES_PER_FRAME * _framesPerScope; + QMutexLocker lock(&_guard); + freeScope(); + allocateScope(); + } +} + +void Audio::freeScope() { + if (_scopeInput) { + delete _scopeInput; + _scopeInput = 0; + } + if (_scopeOutputLeft) { + delete _scopeOutputLeft; + _scopeOutputLeft = 0; + } + if (_scopeOutputRight) { + delete _scopeOutputRight; + _scopeOutputRight = 0; } } void Audio::addBufferToScope( - QByteArray& byteArray, unsigned int frameOffset, const int16_t* source, unsigned int sourceChannel, unsigned int sourceNumberOfChannels) { + QByteArray* byteArray, unsigned int frameOffset, const int16_t* source, unsigned int sourceChannel, unsigned int sourceNumberOfChannels) { // Constant multiplier to map sample value to vertical size of scope float multiplier = (float)MULTIPLIER_SCOPE_HEIGHT / logf(2.0f); @@ -1089,8 +1139,9 @@ void Audio::addBufferToScope( // Temporary variable receives mapping of sample value int16_t value; + QMutexLocker lock(&_guard); // Short int pointer to mapped samples in byte array - int16_t* destination = (int16_t*) byteArray.data(); + int16_t* destination = (int16_t*) byteArray->data(); for (unsigned int i = 0; i < NETWORK_SAMPLES_PER_FRAME; i++) { sample = (float)source[i * sourceNumberOfChannels + sourceChannel]; @@ -1116,18 +1167,20 @@ void Audio::renderScope(int width, int height) { static const float outputLeftColor[4] = { 0.7f, .3f, 0.3f, 0.6f }; static const float outputRightColor[4] = { 0.3f, .3f, 0.7f, 0.6f }; static const int gridRows = 2; - static const int gridCols = 5; + int gridCols = _framesPerScope; - int x = (width - SAMPLES_PER_SCOPE_WIDTH) / 2; - int y = (height - SAMPLES_PER_SCOPE_HEIGHT) / 2; - int w = SAMPLES_PER_SCOPE_WIDTH; - int h = SAMPLES_PER_SCOPE_HEIGHT; + int x = (width - SCOPE_WIDTH) / 2; + int y = (height - SCOPE_HEIGHT) / 2; + int w = SCOPE_WIDTH; + int h = SCOPE_HEIGHT; renderBackground(backgroundColor, x, y, w, h); renderGrid(gridColor, x, y, w, h, gridRows, gridCols); - renderLineStrip(inputColor, x, y, w, _scopeInputOffset, _scopeInput); - renderLineStrip(outputLeftColor, x, y, w, _scopeOutputOffset, _scopeOutputLeft); - renderLineStrip(outputRightColor, x, y, w, _scopeOutputOffset, _scopeOutputRight); + + QMutexLocker lock(&_guard); + renderLineStrip(inputColor, x, y, _samplesPerScope, _scopeInputOffset, _scopeInput); + renderLineStrip(outputLeftColor, x, y, _samplesPerScope, _scopeOutputOffset, _scopeOutputLeft); + renderLineStrip(outputRightColor, x, y, _samplesPerScope, _scopeOutputOffset, _scopeOutputRight); } void Audio::renderBackground(const float* color, int x, int y, int width, int height) { @@ -1170,21 +1223,54 @@ void Audio::renderGrid(const float* color, int x, int y, int width, int height, glColor4f(1, 1, 1, 1); } -void Audio::renderLineStrip(const float* color, int x, int y, int n, int offset, const QByteArray& byteArray) { +void Audio::renderLineStrip(const float* color, int x, int y, int n, int offset, const QByteArray* byteArray) { glColor4fv(color); glBegin(GL_LINE_STRIP); int16_t sample; - int16_t* samples = ((int16_t*) byteArray.data()) + offset; - y += SAMPLES_PER_SCOPE_HEIGHT / 2; - for (int i = n - offset; --i >= 0; ) { - sample = *samples++; + int16_t* samples = ((int16_t*) byteArray->data()) + offset; + int numSamplesToAverage = _framesPerScope / DEFAULT_FRAMES_PER_SCOPE; + int count = (n - offset) / numSamplesToAverage; + int remainder = (n - offset) % numSamplesToAverage; + y += SCOPE_HEIGHT / 2; + + // Compute and draw the sample averages from the offset position + for (int i = count; --i >= 0; ) { + sample = 0; + for (int j = numSamplesToAverage; --j >= 0; ) { + sample += *samples++; + } + sample /= numSamplesToAverage; glVertex2i(x++, y - sample); } - samples = (int16_t*) byteArray.data(); - for (int i = offset; --i >= 0; ) { - sample = *samples++; + + // Compute and draw the sample average across the wrap boundary + if (remainder != 0) { + sample = 0; + for (int j = remainder; --j >= 0; ) { + sample += *samples++; + } + + samples = (int16_t*) byteArray->data(); + + for (int j = numSamplesToAverage - remainder; --j >= 0; ) { + sample += *samples++; + } + sample /= numSamplesToAverage; + glVertex2i(x++, y - sample); + } else { + samples = (int16_t*) byteArray->data(); + } + + // Compute and draw the sample average from the beginning to the offset + count = (offset - remainder) / numSamplesToAverage; + for (int i = count; --i >= 0; ) { + sample = 0; + for (int j = numSamplesToAverage; --j >= 0; ) { + sample += *samples++; + } + sample /= numSamplesToAverage; glVertex2i(x++, y - sample); } glEnd(); diff --git a/interface/src/Audio.h b/interface/src/Audio.h index 277c606d4b..79f0f84ff5 100644 --- a/interface/src/Audio.h +++ b/interface/src/Audio.h @@ -85,6 +85,9 @@ public slots: void toggleScope(); void toggleScopePause(); void toggleAudioSpatialProcessing(); + void selectAudioScopeFiveFrames(); + void selectAudioScopeTwentyFrames(); + void selectAudioScopeFiftyFrames(); virtual void handleAudioByteArray(const QByteArray& audioByteArray); @@ -197,28 +200,36 @@ private: int calculateNumberOfFrameSamples(int numBytes); float calculateDeviceToNetworkInputRatio(int numBytes); + // Audio scope methods for allocation/deallocation + void allocateScope(); + void freeScope(); + void reallocateScope(int frames); + // Audio scope methods for data acquisition void addBufferToScope( - QByteArray& byteArray, unsigned int frameOffset, const int16_t* source, unsigned int sourceChannel, unsigned int sourceNumberOfChannels); + QByteArray* byteArray, unsigned int frameOffset, const int16_t* source, unsigned int sourceChannel, unsigned int sourceNumberOfChannels); // Audio scope methods for rendering void renderBackground(const float* color, int x, int y, int width, int height); void renderGrid(const float* color, int x, int y, int width, int height, int rows, int cols); - void renderLineStrip(const float* color, int x, int y, int n, int offset, const QByteArray& byteArray); + void renderLineStrip(const float* color, int x, int y, int n, int offset, const QByteArray* byteArray); // Audio scope data static const unsigned int NETWORK_SAMPLES_PER_FRAME = NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL; - static const unsigned int FRAMES_PER_SCOPE = 5; - static const unsigned int SAMPLES_PER_SCOPE_WIDTH = FRAMES_PER_SCOPE * NETWORK_SAMPLES_PER_FRAME; + static const unsigned int DEFAULT_FRAMES_PER_SCOPE = 5; + static const unsigned int SCOPE_WIDTH = NETWORK_SAMPLES_PER_FRAME * DEFAULT_FRAMES_PER_SCOPE; static const unsigned int MULTIPLIER_SCOPE_HEIGHT = 20; - static const unsigned int SAMPLES_PER_SCOPE_HEIGHT = 2 * 15 * MULTIPLIER_SCOPE_HEIGHT; + static const unsigned int SCOPE_HEIGHT = 2 * 15 * MULTIPLIER_SCOPE_HEIGHT; bool _scopeEnabled; bool _scopeEnabledPause; int _scopeInputOffset; int _scopeOutputOffset; - QByteArray _scopeInput; - QByteArray _scopeOutputLeft; - QByteArray _scopeOutputRight; + int _framesPerScope; + int _samplesPerScope; + QMutex _guard; + QByteArray* _scopeInput; + QByteArray* _scopeOutputLeft; + QByteArray* _scopeOutputRight; }; diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 92121e719a..45b4089a11 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -417,7 +417,8 @@ Menu::Menu() : false, appInstance->getAudio(), SLOT(toggleToneInjection())); - addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::AudioScope, Qt::CTRL | Qt::Key_P, false, + addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::AudioScope, + Qt::CTRL | Qt::Key_P, false, appInstance->getAudio(), SLOT(toggleScope())); addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::AudioScopePause, @@ -426,6 +427,33 @@ Menu::Menu() : appInstance->getAudio(), SLOT(toggleScopePause())); + QMenu* audioScopeMenu = audioDebugMenu->addMenu("Audio Scope Options"); + addDisabledActionAndSeparator(audioScopeMenu, "Display Frames"); + { + QAction *fiveFrames = addCheckableActionToQMenuAndActionHash(audioScopeMenu, MenuOption::AudioScopeFiveFrames, + 0, + true, + appInstance->getAudio(), + SLOT(selectAudioScopeFiveFrames())); + + QAction *twentyFrames = addCheckableActionToQMenuAndActionHash(audioScopeMenu, MenuOption::AudioScopeTwentyFrames, + 0, + false, + appInstance->getAudio(), + SLOT(selectAudioScopeTwentyFrames())); + + QAction *fiftyFrames = addCheckableActionToQMenuAndActionHash(audioScopeMenu, MenuOption::AudioScopeFiftyFrames, + 0, + false, + appInstance->getAudio(), + SLOT(selectAudioScopeFiftyFrames())); + + QActionGroup* audioScopeFramesGroup = new QActionGroup(audioScopeMenu); + audioScopeFramesGroup->addAction(fiveFrames); + audioScopeFramesGroup->addAction(twentyFrames); + audioScopeFramesGroup->addAction(fiftyFrames); + } + QMenu* spatialAudioMenu = audioDebugMenu->addMenu("Spatial Audio"); addCheckableActionToQMenuAndActionHash(spatialAudioMenu, MenuOption::AudioSpatialProcessing, diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 70f4f62ce4..012dc1662c 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -279,6 +279,10 @@ namespace MenuOption { const QString AudioNoiseReduction = "Audio Noise Reduction"; const QString AudioScope = "Audio Scope"; const QString AudioScopePause = "Pause Audio Scope"; + const QString AudioScopeFrames = "Display Frames"; + const QString AudioScopeFiveFrames = "Five"; + const QString AudioScopeTwentyFrames = "Twenty"; + const QString AudioScopeFiftyFrames = "Fifty"; const QString AudioToneInjection = "Inject Test Tone"; const QString AudioSpatialProcessing = "Audio Spatial Processing"; const QString AudioSpatialProcessingHeadOriented = "Head Oriented";