mirror of
https://github.com/lubosz/overte.git
synced 2025-04-24 14:03:17 +02:00
Merge branch 'master' of https://github.com/highfidelity/hifi into metavoxels
This commit is contained in:
commit
fb64d22171
39 changed files with 630 additions and 114 deletions
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -50,5 +50,9 @@ interface/external/faceplus/*
|
|||
interface/external/priovr/*
|
||||
!interface/external/priovr/readme.txt
|
||||
|
||||
# Ignore RtMidi
|
||||
interface/external/rtmidi/*
|
||||
!interface/external/rtmidi/readme.txt
|
||||
|
||||
# Ignore interfaceCache for Linux users
|
||||
interface/interfaceCache/
|
||||
|
|
|
@ -210,12 +210,12 @@ void Agent::run() {
|
|||
|
||||
NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
|
||||
QNetworkReply *reply = networkAccessManager.get(QNetworkRequest(scriptURL));
|
||||
QNetworkDiskCache* cache = new QNetworkDiskCache(&networkAccessManager);
|
||||
|
||||
QNetworkDiskCache* cache = new QNetworkDiskCache();
|
||||
QString cachePath = QStandardPaths::writableLocation(QStandardPaths::DataLocation);
|
||||
cache->setCacheDirectory(!cachePath.isEmpty() ? cachePath : "agentCache");
|
||||
QMetaObject::invokeMethod(&networkAccessManager, "setCache",
|
||||
Qt::BlockingQueuedConnection,
|
||||
Q_ARG(QAbstractNetworkCache*, cache));
|
||||
cache->moveToThread(networkAccessManager.thread());
|
||||
networkAccessManager.setCache(cache);
|
||||
|
||||
qDebug() << "Downloading script at" << scriptURL.toString();
|
||||
|
||||
|
@ -270,4 +270,5 @@ void Agent::run() {
|
|||
|
||||
void Agent::aboutToFinish() {
|
||||
_scriptEngine.stop();
|
||||
NetworkAccessManager::getInstance().clearAccessCache();
|
||||
}
|
||||
|
|
|
@ -89,6 +89,10 @@ AudioMixer::~AudioMixer() {
|
|||
delete _listenerUnattenuatedZone;
|
||||
}
|
||||
|
||||
const float ATTENUATION_BEGINS_AT_DISTANCE = 1.0f;
|
||||
const float ATTENUATION_AMOUNT_PER_DOUBLING_IN_DISTANCE = 0.18f;
|
||||
const float ATTENUATION_EPSILON_DISTANCE = 0.1f;
|
||||
|
||||
void AudioMixer::addBufferToMixForListeningNodeWithBuffer(PositionalAudioRingBuffer* bufferToAdd,
|
||||
AvatarAudioRingBuffer* listeningNodeBuffer) {
|
||||
float bearingRelativeAngleToSource = 0.0f;
|
||||
|
@ -104,7 +108,7 @@ void AudioMixer::addBufferToMixForListeningNodeWithBuffer(PositionalAudioRingBuf
|
|||
glm::vec3 relativePosition = bufferToAdd->getPosition() - listeningNodeBuffer->getPosition();
|
||||
|
||||
float distanceBetween = glm::length(relativePosition);
|
||||
|
||||
|
||||
if (distanceBetween < EPSILON) {
|
||||
distanceBetween = EPSILON;
|
||||
}
|
||||
|
@ -121,6 +125,12 @@ void AudioMixer::addBufferToMixForListeningNodeWithBuffer(PositionalAudioRingBuf
|
|||
shouldAttenuate = !bufferToAdd->getListenerUnattenuatedZone()->contains(listeningNodeBuffer->getPosition());
|
||||
}
|
||||
|
||||
if (bufferToAdd->getType() == PositionalAudioRingBuffer::Injector) {
|
||||
attenuationCoefficient *= reinterpret_cast<InjectedAudioRingBuffer*>(bufferToAdd)->getAttenuationRatio();
|
||||
}
|
||||
|
||||
shouldAttenuate = shouldAttenuate && distanceBetween > ATTENUATION_EPSILON_DISTANCE;
|
||||
|
||||
if (shouldAttenuate) {
|
||||
glm::quat inverseOrientation = glm::inverse(listeningNodeBuffer->getOrientation());
|
||||
|
||||
|
@ -128,9 +138,7 @@ void AudioMixer::addBufferToMixForListeningNodeWithBuffer(PositionalAudioRingBuf
|
|||
float radius = 0.0f;
|
||||
|
||||
if (bufferToAdd->getType() == PositionalAudioRingBuffer::Injector) {
|
||||
InjectedAudioRingBuffer* injectedBuffer = (InjectedAudioRingBuffer*) bufferToAdd;
|
||||
radius = injectedBuffer->getRadius();
|
||||
attenuationCoefficient *= injectedBuffer->getAttenuationRatio();
|
||||
radius = reinterpret_cast<InjectedAudioRingBuffer*>(bufferToAdd)->getRadius();
|
||||
}
|
||||
|
||||
if (radius == 0 || (distanceSquareToSource > radius * radius)) {
|
||||
|
@ -155,7 +163,7 @@ void AudioMixer::addBufferToMixForListeningNodeWithBuffer(PositionalAudioRingBuf
|
|||
const float OFF_AXIS_ATTENUATION_FORMULA_STEP = (1 - MAX_OFF_AXIS_ATTENUATION) / 2.0f;
|
||||
|
||||
float offAxisCoefficient = MAX_OFF_AXIS_ATTENUATION +
|
||||
(OFF_AXIS_ATTENUATION_FORMULA_STEP * (angleOfDelivery / PI_OVER_TWO));
|
||||
(OFF_AXIS_ATTENUATION_FORMULA_STEP * (angleOfDelivery / PI_OVER_TWO));
|
||||
|
||||
// multiply the current attenuation coefficient by the calculated off axis coefficient
|
||||
attenuationCoefficient *= offAxisCoefficient;
|
||||
|
@ -163,19 +171,18 @@ void AudioMixer::addBufferToMixForListeningNodeWithBuffer(PositionalAudioRingBuf
|
|||
|
||||
glm::vec3 rotatedSourcePosition = inverseOrientation * relativePosition;
|
||||
|
||||
const float DISTANCE_SCALE = 2.5f;
|
||||
const float GEOMETRIC_AMPLITUDE_SCALAR = 0.3f;
|
||||
const float DISTANCE_LOG_BASE = 2.5f;
|
||||
const float DISTANCE_SCALE_LOG = logf(DISTANCE_SCALE) / logf(DISTANCE_LOG_BASE);
|
||||
|
||||
// calculate the distance coefficient using the distance to this node
|
||||
float distanceCoefficient = powf(GEOMETRIC_AMPLITUDE_SCALAR,
|
||||
DISTANCE_SCALE_LOG +
|
||||
(0.5f * logf(distanceSquareToSource) / logf(DISTANCE_LOG_BASE)) - 1);
|
||||
distanceCoefficient = std::min(1.0f, distanceCoefficient);
|
||||
|
||||
// multiply the current attenuation coefficient by the distance coefficient
|
||||
attenuationCoefficient *= distanceCoefficient;
|
||||
if (distanceBetween >= ATTENUATION_BEGINS_AT_DISTANCE) {
|
||||
// calculate the distance coefficient using the distance to this node
|
||||
float distanceCoefficient = 1 - (logf(distanceBetween / ATTENUATION_BEGINS_AT_DISTANCE) / logf(2.0f)
|
||||
* ATTENUATION_AMOUNT_PER_DOUBLING_IN_DISTANCE);
|
||||
|
||||
if (distanceCoefficient < 0) {
|
||||
distanceCoefficient = 0;
|
||||
}
|
||||
|
||||
// multiply the current attenuation coefficient by the distance coefficient
|
||||
attenuationCoefficient *= distanceCoefficient;
|
||||
}
|
||||
|
||||
// project the rotated source position vector onto the XZ plane
|
||||
rotatedSourcePosition.y = 0.0f;
|
||||
|
|
|
@ -101,8 +101,7 @@ int AudioMixerClientData::parseData(const QByteArray& packet) {
|
|||
|
||||
if (!matchingInjectedRingBuffer) {
|
||||
// we don't have a matching injected audio ring buffer, so add it
|
||||
matchingInjectedRingBuffer = new InjectedAudioRingBuffer(streamIdentifier,
|
||||
AudioMixer::getUseDynamicJitterBuffers());
|
||||
matchingInjectedRingBuffer = new InjectedAudioRingBuffer(streamIdentifier, AudioMixer::getUseDynamicJitterBuffers());
|
||||
_ringBuffers.push_back(matchingInjectedRingBuffer);
|
||||
}
|
||||
|
||||
|
|
|
@ -216,9 +216,13 @@ int OctreeInboundPacketProcessor::sendNackPackets() {
|
|||
}
|
||||
|
||||
const SharedNodePointer& destinationNode = NodeList::getInstance()->getNodeHash().value(nodeUUID);
|
||||
const QSet<unsigned short int>& missingSequenceNumbers = nodeStats.getIncomingEditSequenceNumberStats().getMissingSet();
|
||||
|
||||
// retrieve sequence number stats of node, prune its missing set
|
||||
SequenceNumberStats& sequenceNumberStats = nodeStats.getIncomingEditSequenceNumberStats();
|
||||
sequenceNumberStats.pruneMissingSet();
|
||||
|
||||
// construct nack packet(s) for this node
|
||||
const QSet<unsigned short int>& missingSequenceNumbers = sequenceNumberStats.getMissingSet();
|
||||
int numSequenceNumbersAvailable = missingSequenceNumbers.size();
|
||||
QSet<unsigned short int>::const_iterator missingSequenceNumberIterator = missingSequenceNumbers.constBegin();
|
||||
while (numSequenceNumbersAvailable > 0) {
|
||||
|
|
|
@ -35,6 +35,7 @@ public:
|
|||
{ return _totalElementsInPacket == 0 ? 0 : _totalLockWaitTime / _totalElementsInPacket; }
|
||||
|
||||
const SequenceNumberStats& getIncomingEditSequenceNumberStats() const { return _incomingEditSequenceNumberStats; }
|
||||
SequenceNumberStats& getIncomingEditSequenceNumberStats() { return _incomingEditSequenceNumberStats; }
|
||||
|
||||
void trackInboundPacket(unsigned short int incomingSequence, quint64 transitTime,
|
||||
int editsInPacket, quint64 processTime, quint64 lockWaitTime);
|
||||
|
|
|
@ -42,7 +42,7 @@ OctreeQueryNode::OctreeQueryNode() :
|
|||
_lastRootTimestamp(0),
|
||||
_myPacketType(PacketTypeUnknown),
|
||||
_isShuttingDown(false),
|
||||
_sentPacketHistory(1000)
|
||||
_sentPacketHistory()
|
||||
{
|
||||
}
|
||||
|
||||
|
|
33
cmake/modules/FindRtMidi.cmake
Normal file
33
cmake/modules/FindRtMidi.cmake
Normal file
|
@ -0,0 +1,33 @@
|
|||
#
|
||||
# FindRtMidd.cmake
|
||||
#
|
||||
# Try to find the RtMidi library
|
||||
#
|
||||
# You can provide a RTMIDI_ROOT_DIR which contains lib and include directories
|
||||
#
|
||||
# Once done this will define
|
||||
#
|
||||
# RTMIDI_FOUND - system found RtMidi
|
||||
# RTMIDI_INCLUDE_DIRS - the RtMidi include directory
|
||||
# RTMIDI_CPP - Include this with src to use RtMidi
|
||||
#
|
||||
# Created on 6/30/2014 by Stephen Birarda
|
||||
# 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
|
||||
#
|
||||
|
||||
if (RTMIDI_LIBRARIES AND RTMIDI_INCLUDE_DIRS)
|
||||
# in cache already
|
||||
set(RTMIDI_FOUND TRUE)
|
||||
else ()
|
||||
|
||||
set(RTMIDI_SEARCH_DIRS "${RTMIDI_ROOT_DIR}" "$ENV{HIFI_LIB_DIR}/rtmidi")
|
||||
|
||||
find_path(RTMIDI_INCLUDE_DIR RtMidi.h PATH_SUFFIXES include HINTS ${RTMIDI_SEARCH_DIRS})
|
||||
find_file(RTMIDI_CPP NAMES RtMidi.cpp PATH_SUFFIXES src HINTS ${RTMIDI_SEARCH_DIRS})
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(RTMIDI DEFAULT_MSG RTMIDI_INCLUDE_DIR RTMIDI_CPP)
|
||||
endif ()
|
32
examples/animationStateExample.js
Normal file
32
examples/animationStateExample.js
Normal file
|
@ -0,0 +1,32 @@
|
|||
//
|
||||
// animationStateExample.js
|
||||
// examples
|
||||
//
|
||||
// Created by Brad Hefta-Gaub on 7/3/14.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// This is an example script that runs in a loop and displays a counter to the log
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
//
|
||||
|
||||
var count = 0;
|
||||
|
||||
function displayAnimationDetails(deltaTime) {
|
||||
print("count =" + count + " deltaTime=" + deltaTime);
|
||||
count++;
|
||||
var animationDetails = MyAvatar.getAnimationDetailsByRole("idle");
|
||||
print("animationDetails.frameIndex=" + animationDetails.frameIndex);
|
||||
}
|
||||
|
||||
function scriptEnding() {
|
||||
print("SCRIPT ENDNG!!!\n");
|
||||
}
|
||||
|
||||
// register the call back so it fires before each data send
|
||||
Script.update.connect(displayAnimationDetails);
|
||||
|
||||
// register our scriptEnding callback
|
||||
Script.scriptEnding.connect(scriptEnding);
|
|
@ -18,6 +18,7 @@ set(LIBOVR_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/external/oculus")
|
|||
set(PRIOVR_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/external/priovr")
|
||||
set(SIXENSE_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/external/Sixense")
|
||||
set(VISAGE_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/external/visage")
|
||||
set(RTMIDI_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/external/rtmidi")
|
||||
|
||||
find_package(Qt5LinguistTools REQUIRED)
|
||||
find_package(Qt5LinguistToolsMacros)
|
||||
|
@ -110,6 +111,16 @@ if (APPLE)
|
|||
SET(INTERFACE_SRCS ${INTERFACE_SRCS} "${CMAKE_CURRENT_SOURCE_DIR}/interface.icns")
|
||||
endif()
|
||||
|
||||
# RtMidi for scripted MIDI control
|
||||
find_package(RtMidi)
|
||||
|
||||
if (RTMIDI_FOUND AND NOT DISABLE_RTMIDI)
|
||||
add_definitions(-DHAVE_RTMIDI)
|
||||
include_directories(SYSTEM ${RTMIDI_INCLUDE_DIR})
|
||||
|
||||
set(INTERFACE_SRCS ${INTERFACE_SRCS} "${RTMIDI_CPP}")
|
||||
endif ()
|
||||
|
||||
# create the executable, make it a bundle on OS X
|
||||
add_executable(${TARGET_NAME} MACOSX_BUNDLE ${INTERFACE_SRCS} ${QM})
|
||||
|
||||
|
@ -143,75 +154,82 @@ find_package(Qxmpp)
|
|||
|
||||
# include the Sixense library for Razer Hydra if available
|
||||
if (SIXENSE_FOUND AND NOT DISABLE_SIXENSE)
|
||||
add_definitions(-DHAVE_SIXENSE)
|
||||
include_directories(SYSTEM "${SIXENSE_INCLUDE_DIRS}")
|
||||
if (APPLE OR UNIX)
|
||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -isystem ${SIXENSE_INCLUDE_DIRS}")
|
||||
endif (APPLE OR UNIX)
|
||||
target_link_libraries(${TARGET_NAME} "${SIXENSE_LIBRARIES}")
|
||||
add_definitions(-DHAVE_SIXENSE)
|
||||
include_directories(SYSTEM "${SIXENSE_INCLUDE_DIRS}")
|
||||
if (APPLE OR UNIX)
|
||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -isystem ${SIXENSE_INCLUDE_DIRS}")
|
||||
endif (APPLE OR UNIX)
|
||||
target_link_libraries(${TARGET_NAME} "${SIXENSE_LIBRARIES}")
|
||||
endif (SIXENSE_FOUND AND NOT DISABLE_SIXENSE)
|
||||
|
||||
# likewise with Visage library for webcam feature tracking
|
||||
if (VISAGE_FOUND AND NOT DISABLE_VISAGE)
|
||||
add_definitions(-DHAVE_VISAGE -DVISAGE_STATIC)
|
||||
include_directories(SYSTEM "${VISAGE_INCLUDE_DIRS}")
|
||||
if (APPLE)
|
||||
add_definitions(-DMAC_OS_X)
|
||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-comment")
|
||||
include_directories(SYSTEM "${VISAGE_INCLUDE_DIRS}")
|
||||
find_library(AVFoundation AVFoundation)
|
||||
find_library(CoreMedia CoreMedia)
|
||||
find_library(NEW_STD_LIBRARY libc++.dylib /usr/lib/)
|
||||
target_link_libraries(${TARGET_NAME} ${AVFoundation} ${CoreMedia} ${NEW_STD_LIBRARY})
|
||||
endif (APPLE)
|
||||
target_link_libraries(${TARGET_NAME} "${VISAGE_LIBRARIES}")
|
||||
add_definitions(-DHAVE_VISAGE -DVISAGE_STATIC)
|
||||
include_directories(SYSTEM "${VISAGE_INCLUDE_DIRS}")
|
||||
if (APPLE)
|
||||
add_definitions(-DMAC_OS_X)
|
||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-comment")
|
||||
include_directories(SYSTEM "${VISAGE_INCLUDE_DIRS}")
|
||||
find_library(AVFoundation AVFoundation)
|
||||
find_library(CoreMedia CoreMedia)
|
||||
find_library(NEW_STD_LIBRARY libc++.dylib /usr/lib/)
|
||||
target_link_libraries(${TARGET_NAME} ${AVFoundation} ${CoreMedia} ${NEW_STD_LIBRARY})
|
||||
endif (APPLE)
|
||||
target_link_libraries(${TARGET_NAME} "${VISAGE_LIBRARIES}")
|
||||
endif (VISAGE_FOUND AND NOT DISABLE_VISAGE)
|
||||
|
||||
# and with Faceplus library, also for webcam feature tracking
|
||||
if (FACEPLUS_FOUND AND NOT DISABLE_FACEPLUS)
|
||||
add_definitions(-DHAVE_FACEPLUS)
|
||||
include_directories(SYSTEM "${FACEPLUS_INCLUDE_DIRS}")
|
||||
target_link_libraries(${TARGET_NAME} "${FACEPLUS_LIBRARIES}")
|
||||
add_definitions(-DHAVE_FACEPLUS)
|
||||
include_directories(SYSTEM "${FACEPLUS_INCLUDE_DIRS}")
|
||||
target_link_libraries(${TARGET_NAME} "${FACEPLUS_LIBRARIES}")
|
||||
endif (FACEPLUS_FOUND AND NOT DISABLE_FACEPLUS)
|
||||
|
||||
# and with LibOVR for Oculus Rift
|
||||
if (LIBOVR_FOUND AND NOT DISABLE_LIBOVR)
|
||||
add_definitions(-DHAVE_LIBOVR)
|
||||
include_directories(SYSTEM "${LIBOVR_INCLUDE_DIRS}")
|
||||
add_definitions(-DHAVE_LIBOVR)
|
||||
include_directories(SYSTEM "${LIBOVR_INCLUDE_DIRS}")
|
||||
|
||||
if (APPLE OR UNIX)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -isystem ${LIBOVR_INCLUDE_DIRS}")
|
||||
endif ()
|
||||
if (APPLE OR UNIX)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -isystem ${LIBOVR_INCLUDE_DIRS}")
|
||||
endif ()
|
||||
|
||||
if (WIN32)
|
||||
target_link_libraries(${TARGET_NAME} optimized "${LIBOVR_RELEASE_LIBRARIES}" debug "${LIBOVR_DEBUG_LIBRARIES}")
|
||||
else()
|
||||
target_link_libraries(${TARGET_NAME} "${LIBOVR_LIBRARIES}")
|
||||
endif()
|
||||
if (WIN32)
|
||||
target_link_libraries(${TARGET_NAME} optimized "${LIBOVR_RELEASE_LIBRARIES}" debug "${LIBOVR_DEBUG_LIBRARIES}")
|
||||
else ()
|
||||
target_link_libraries(${TARGET_NAME} "${LIBOVR_LIBRARIES}")
|
||||
endif ()
|
||||
endif (LIBOVR_FOUND AND NOT DISABLE_LIBOVR)
|
||||
|
||||
# and with PrioVR library
|
||||
if (PRIOVR_FOUND AND NOT DISABLE_PRIOVR)
|
||||
add_definitions(-DHAVE_PRIOVR)
|
||||
include_directories(SYSTEM "${PRIOVR_INCLUDE_DIRS}")
|
||||
target_link_libraries(${TARGET_NAME} "${PRIOVR_LIBRARIES}")
|
||||
add_definitions(-DHAVE_PRIOVR)
|
||||
include_directories(SYSTEM "${PRIOVR_INCLUDE_DIRS}")
|
||||
target_link_libraries(${TARGET_NAME} "${PRIOVR_LIBRARIES}")
|
||||
endif (PRIOVR_FOUND AND NOT DISABLE_PRIOVR)
|
||||
|
||||
# and with SDL for joysticks
|
||||
if (SDL_FOUND AND NOT DISABLE_SDL)
|
||||
add_definitions(-DHAVE_SDL)
|
||||
include_directories(SYSTEM "${SDL_INCLUDE_DIR}")
|
||||
target_link_libraries(${TARGET_NAME} "${SDL_LIBRARY}")
|
||||
add_definitions(-DHAVE_SDL)
|
||||
include_directories(SYSTEM "${SDL_INCLUDE_DIR}")
|
||||
target_link_libraries(${TARGET_NAME} "${SDL_LIBRARY}")
|
||||
endif (SDL_FOUND AND NOT DISABLE_SDL)
|
||||
|
||||
# and with qxmpp for chat
|
||||
if (QXMPP_FOUND AND NOT DISABLE_QXMPP)
|
||||
add_definitions(-DHAVE_QXMPP -DQXMPP_STATIC)
|
||||
include_directories(SYSTEM ${QXMPP_INCLUDE_DIR})
|
||||
add_definitions(-DHAVE_QXMPP -DQXMPP_STATIC)
|
||||
include_directories(SYSTEM ${QXMPP_INCLUDE_DIR})
|
||||
|
||||
target_link_libraries(${TARGET_NAME} "${QXMPP_LIBRARY}")
|
||||
target_link_libraries(${TARGET_NAME} "${QXMPP_LIBRARY}")
|
||||
endif (QXMPP_FOUND AND NOT DISABLE_QXMPP)
|
||||
|
||||
# link CoreMIDI if we're using RtMidi
|
||||
if (RTMIDI_FOUND AND APPLE)
|
||||
find_library(CoreMIDI CoreMIDI)
|
||||
add_definitions(-D__MACOSX_CORE__)
|
||||
target_link_libraries(${TARGET_NAME} ${CoreMIDI})
|
||||
endif()
|
||||
|
||||
# include headers for interface and InterfaceConfig.
|
||||
include_directories("${PROJECT_SOURCE_DIR}/src" "${PROJECT_BINARY_DIR}/includes")
|
||||
|
||||
|
|
41
interface/external/rtmidi/readme.txt
vendored
Normal file
41
interface/external/rtmidi/readme.txt
vendored
Normal file
|
@ -0,0 +1,41 @@
|
|||
|
||||
Instructions for adding the RtMidi library to Interface
|
||||
Stephen Birarda, June 30, 2014
|
||||
|
||||
1. Download the RtMidi tarball from High Fidelity S3.
|
||||
http://highfidelity-public.s3.amazonaws.com/dependencies/rtmidi-2.1.0.tar.gz
|
||||
|
||||
2. Copy RtMidi.h to externals/rtmidi/include.
|
||||
|
||||
3. Copy RtMidi.cpp to externals/rtmidi/src
|
||||
|
||||
4. Delete your build directory, run cmake and build, and you should be all set.
|
||||
|
||||
=========================
|
||||
|
||||
RtMidi: realtime MIDI i/o C++ classes<BR>
|
||||
Copyright (c) 2003-2014 Gary P. Scavone
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation files
|
||||
(the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
Any person wishing to distribute modifications to the Software is
|
||||
asked to send the modifications to the original developer so that
|
||||
they can be incorporated into the canonical version. This is,
|
||||
however, not a binding provision of this license.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
||||
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@ -70,6 +70,7 @@
|
|||
#include "Menu.h"
|
||||
#include "ModelUploader.h"
|
||||
#include "Util.h"
|
||||
#include "devices/MIDIManager.h"
|
||||
#include "devices/OculusManager.h"
|
||||
#include "devices/TV3DManager.h"
|
||||
#include "renderer/ProgramObject.h"
|
||||
|
@ -315,11 +316,14 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
|
|||
QString cachePath = QStandardPaths::writableLocation(QStandardPaths::DataLocation);
|
||||
|
||||
NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
|
||||
QNetworkDiskCache* cache = new QNetworkDiskCache(&networkAccessManager);
|
||||
|
||||
// Make sure cache on same thread than its parent (NetworkAccessManager)
|
||||
QNetworkDiskCache* cache = new QNetworkDiskCache();
|
||||
cache->moveToThread(networkAccessManager.thread());
|
||||
cache->setParent(&networkAccessManager);
|
||||
|
||||
cache->setCacheDirectory(!cachePath.isEmpty() ? cachePath : "interfaceCache");
|
||||
QMetaObject::invokeMethod(&networkAccessManager, "setCache",
|
||||
Qt::BlockingQueuedConnection,
|
||||
Q_ARG(QAbstractNetworkCache*, cache));
|
||||
networkAccessManager.setCache(cache);
|
||||
|
||||
ResourceCache::setRequestLimit(3);
|
||||
|
||||
|
@ -396,6 +400,12 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
|
|||
OAuthWebViewHandler::addHighFidelityRootCAToSSLConfig();
|
||||
|
||||
_trayIcon->show();
|
||||
|
||||
#ifdef HAVE_RTMIDI
|
||||
// setup the MIDIManager
|
||||
MIDIManager& midiManagerInstance = MIDIManager::getInstance();
|
||||
midiManagerInstance.openDefaultPort();
|
||||
#endif
|
||||
}
|
||||
|
||||
Application::~Application() {
|
||||
|
@ -2184,11 +2194,11 @@ int Application::sendNackPackets() {
|
|||
_octreeSceneStatsLock.unlock();
|
||||
continue;
|
||||
}
|
||||
OctreeSceneStats& stats = _octreeServerSceneStats[nodeUUID];
|
||||
|
||||
// make copy of missing sequence numbers from stats
|
||||
const QSet<OCTREE_PACKET_SEQUENCE> missingSequenceNumbers =
|
||||
stats.getIncomingOctreeSequenceNumberStats().getMissingSet();
|
||||
// get sequence number stats of node, prune its missing set, and make a copy of the missing set
|
||||
SequenceNumberStats& sequenceNumberStats = _octreeServerSceneStats[nodeUUID].getIncomingOctreeSequenceNumberStats();
|
||||
sequenceNumberStats.pruneMissingSet();
|
||||
const QSet<OCTREE_PACKET_SEQUENCE> missingSequenceNumbers = sequenceNumberStats.getMissingSet();
|
||||
|
||||
_octreeSceneStatsLock.unlock();
|
||||
|
||||
|
@ -3625,6 +3635,10 @@ ScriptEngine* Application::loadScript(const QString& scriptName, bool loadScript
|
|||
scriptEngine->registerGlobalObject("AnimationCache", &_animationCache);
|
||||
scriptEngine->registerGlobalObject("AudioReflector", &_audioReflector);
|
||||
scriptEngine->registerGlobalObject("Account", AccountScriptingInterface::getInstance());
|
||||
|
||||
#ifdef HAVE_RTMIDI
|
||||
scriptEngine->registerGlobalObject("MIDI", &MIDIManager::getInstance());
|
||||
#endif
|
||||
|
||||
QThread* workerThread = new QThread(this);
|
||||
|
||||
|
|
|
@ -67,7 +67,7 @@ Audio::Audio(int16_t initialJitterBufferSamples, QObject* parent) :
|
|||
_proceduralAudioOutput(NULL),
|
||||
_proceduralOutputDevice(NULL),
|
||||
_inputRingBuffer(0),
|
||||
_ringBuffer(NETWORK_BUFFER_LENGTH_BYTES_PER_CHANNEL),
|
||||
_ringBuffer(NETWORK_BUFFER_LENGTH_SAMPLES_STEREO),
|
||||
_isStereoInput(false),
|
||||
_averagedLatency(0.0),
|
||||
_measuredJitter(0),
|
||||
|
@ -93,7 +93,7 @@ Audio::Audio(int16_t initialJitterBufferSamples, QObject* parent) :
|
|||
_processSpatialAudio(false),
|
||||
_spatialAudioStart(0),
|
||||
_spatialAudioFinish(0),
|
||||
_spatialAudioRingBuffer(NETWORK_BUFFER_LENGTH_BYTES_PER_CHANNEL, true), // random access mode
|
||||
_spatialAudioRingBuffer(NETWORK_BUFFER_LENGTH_SAMPLES_STEREO, true), // random access mode
|
||||
_scopeEnabled(false),
|
||||
_scopeEnabledPause(false),
|
||||
_scopeInputOffset(0),
|
||||
|
|
|
@ -149,13 +149,19 @@ void DatagramProcessor::processDatagrams() {
|
|||
break;
|
||||
}
|
||||
case PacketTypeVoxelEditNack:
|
||||
application->_voxelEditSender.processNackPacket(incomingPacket);
|
||||
if (!Menu::getInstance()->isOptionChecked(MenuOption::DisableNackPackets)) {
|
||||
application->_voxelEditSender.processNackPacket(incomingPacket);
|
||||
}
|
||||
break;
|
||||
case PacketTypeParticleEditNack:
|
||||
application->_particleEditSender.processNackPacket(incomingPacket);
|
||||
if (!Menu::getInstance()->isOptionChecked(MenuOption::DisableNackPackets)) {
|
||||
application->_particleEditSender.processNackPacket(incomingPacket);
|
||||
}
|
||||
break;
|
||||
case PacketTypeModelEditNack:
|
||||
application->_modelEditSender.processNackPacket(incomingPacket);
|
||||
if (!Menu::getInstance()->isOptionChecked(MenuOption::DisableNackPackets)) {
|
||||
application->_modelEditSender.processNackPacket(incomingPacket);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
nodeList->processNodeData(senderSockAddr, incomingPacket);
|
||||
|
|
|
@ -551,6 +551,40 @@ void MyAvatar::stopAnimation(const QString& url) {
|
|||
}
|
||||
}
|
||||
|
||||
AnimationDetails MyAvatar::getAnimationDetailsByRole(const QString& role) {
|
||||
AnimationDetails result;
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QMetaObject::invokeMethod(this, "getAnimationDetailsByRole", Qt::BlockingQueuedConnection,
|
||||
Q_RETURN_ARG(AnimationDetails, result),
|
||||
Q_ARG(const QString&, role));
|
||||
return result;
|
||||
}
|
||||
foreach (const AnimationHandlePointer& handle, _skeletonModel.getRunningAnimations()) {
|
||||
if (handle->getRole() == role) {
|
||||
result = handle->getAnimationDetails();
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
AnimationDetails MyAvatar::getAnimationDetails(const QString& url) {
|
||||
AnimationDetails result;
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QMetaObject::invokeMethod(this, "getAnimationDetails", Qt::BlockingQueuedConnection,
|
||||
Q_RETURN_ARG(AnimationDetails, result),
|
||||
Q_ARG(const QString&, url));
|
||||
return result;
|
||||
}
|
||||
foreach (const AnimationHandlePointer& handle, _skeletonModel.getRunningAnimations()) {
|
||||
if (handle->getURL() == url) {
|
||||
result = handle->getAnimationDetails();
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void MyAvatar::saveData(QSettings* settings) {
|
||||
settings->beginGroup("Avatar");
|
||||
|
||||
|
|
|
@ -83,6 +83,9 @@ public:
|
|||
|
||||
/// Stops an animation identified by its role.
|
||||
Q_INVOKABLE void stopAnimationByRole(const QString& role);
|
||||
|
||||
Q_INVOKABLE AnimationDetails getAnimationDetailsByRole(const QString& role);
|
||||
Q_INVOKABLE AnimationDetails getAnimationDetails(const QString& url);
|
||||
|
||||
// get/set avatar data
|
||||
void saveData(QSettings* settings);
|
||||
|
|
68
interface/src/devices/MIDIManager.cpp
Normal file
68
interface/src/devices/MIDIManager.cpp
Normal file
|
@ -0,0 +1,68 @@
|
|||
//
|
||||
// MIDIManager.cpp
|
||||
//
|
||||
//
|
||||
// Created by Stephen Birarda on 2014-06-30.
|
||||
// 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
|
||||
//
|
||||
|
||||
#include <QtCore/QDebug>
|
||||
|
||||
#include "MIDIManager.h"
|
||||
|
||||
#ifdef HAVE_RTMIDI
|
||||
|
||||
MIDIManager& MIDIManager::getInstance() {
|
||||
static MIDIManager sharedInstance;
|
||||
return sharedInstance;
|
||||
}
|
||||
|
||||
void MIDIManager::midiCallback(double deltaTime, std::vector<unsigned char>* message, void* userData) {
|
||||
|
||||
MIDIEvent callbackEvent;
|
||||
callbackEvent.deltaTime = deltaTime;
|
||||
|
||||
callbackEvent.type = message->at(0);
|
||||
|
||||
if (message->size() > 1) {
|
||||
callbackEvent.data1 = message->at(1);
|
||||
}
|
||||
|
||||
if (message->size() > 2) {
|
||||
callbackEvent.data2 = message->at(2);
|
||||
}
|
||||
|
||||
emit getInstance().midiEvent(callbackEvent);
|
||||
}
|
||||
|
||||
MIDIManager::~MIDIManager() {
|
||||
delete _midiInput;
|
||||
}
|
||||
|
||||
const int DEFAULT_MIDI_PORT = 0;
|
||||
|
||||
void MIDIManager::openDefaultPort() {
|
||||
if (!_midiInput) {
|
||||
_midiInput = new RtMidiIn();
|
||||
|
||||
if (_midiInput->getPortCount() > 0) {
|
||||
qDebug() << "MIDIManager opening port" << DEFAULT_MIDI_PORT;
|
||||
|
||||
_midiInput->openPort(DEFAULT_MIDI_PORT);
|
||||
|
||||
// don't ignore sysex, timing, or active sensing messages
|
||||
_midiInput->ignoreTypes(false, false, false);
|
||||
|
||||
_midiInput->setCallback(&MIDIManager::midiCallback);
|
||||
} else {
|
||||
qDebug() << "MIDIManager openDefaultPort called but there are no ports available.";
|
||||
delete _midiInput;
|
||||
_midiInput = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
56
interface/src/devices/MIDIManager.h
Normal file
56
interface/src/devices/MIDIManager.h
Normal file
|
@ -0,0 +1,56 @@
|
|||
//
|
||||
// MIDIManager.h
|
||||
// interface/src/devices
|
||||
//
|
||||
// Created by Stephen Birarda on 2014-06-30.
|
||||
// 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
|
||||
//
|
||||
|
||||
#ifndef hifi_MIDIManager_h
|
||||
#define hifi_MIDIManager_h
|
||||
|
||||
#ifdef HAVE_RTMIDI
|
||||
|
||||
#include <QtCore/QObject>
|
||||
#include <QtScript/QScriptEngine>
|
||||
|
||||
#include <MIDIEvent.h>
|
||||
|
||||
#include <RtMidi.h>
|
||||
|
||||
class MIDIManager : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(unsigned int NoteOn READ NoteOn)
|
||||
Q_PROPERTY(unsigned int NoteOff READ NoteOff)
|
||||
Q_PROPERTY(unsigned int ModWheel READ ModWheel)
|
||||
Q_PROPERTY(unsigned int PitchWheel READ PitchWheel)
|
||||
|
||||
public:
|
||||
static MIDIManager& getInstance();
|
||||
static void midiCallback(double deltaTime, std::vector<unsigned char>* message, void* userData);
|
||||
|
||||
~MIDIManager();
|
||||
|
||||
void openDefaultPort();
|
||||
bool hasDevice() const { return !!_midiInput; }
|
||||
public slots:
|
||||
unsigned int NoteOn() const { return 144; }
|
||||
unsigned int NoteOff() const { return 128; }
|
||||
unsigned int ModWheel() const { return 176; }
|
||||
unsigned int PitchWheel() const { return 224; }
|
||||
signals:
|
||||
void midiEvent(const MIDIEvent& event);
|
||||
|
||||
private:
|
||||
RtMidiIn* _midiInput;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#endif // hifi_MIDIManager_h
|
||||
|
|
@ -71,6 +71,16 @@ void SixenseManager::setFilter(bool filter) {
|
|||
|
||||
void SixenseManager::update(float deltaTime) {
|
||||
#ifdef HAVE_SIXENSE
|
||||
// if the controllers haven't been moved in a while, disable
|
||||
const unsigned int MOVEMENT_DISABLE_SECONDS = 3;
|
||||
if (usecTimestampNow() - _lastMovement > (MOVEMENT_DISABLE_SECONDS * USECS_PER_SECOND)) {
|
||||
Hand* hand = Application::getInstance()->getAvatar()->getHand();
|
||||
for (std::vector<PalmData>::iterator it = hand->getPalms().begin(); it != hand->getPalms().end(); it++) {
|
||||
it->setActive(false);
|
||||
}
|
||||
_lastMovement = usecTimestampNow();
|
||||
}
|
||||
|
||||
if (sixenseGetNumActiveControllers() == 0) {
|
||||
_hydrasConnected = false;
|
||||
return;
|
||||
|
@ -154,6 +164,11 @@ void SixenseManager::update(float deltaTime) {
|
|||
// no latency.
|
||||
float velocityFilter = glm::clamp(1.0f - glm::length(rawVelocity), 0.0f, 1.0f);
|
||||
palm->setRawPosition(palm->getRawPosition() * velocityFilter + position * (1.0f - velocityFilter));
|
||||
|
||||
// adjustment for hydra controllers fit into hands
|
||||
float sign = (i == 0) ? -1.0f : 1.0f;
|
||||
rotation *= glm::angleAxis(sign * PI/4.0f, glm::vec3(0.0f, 0.0f, 1.0f));
|
||||
|
||||
palm->setRawRotation(safeMix(palm->getRawRotation(), rotation, 1.0f - velocityFilter));
|
||||
|
||||
// use the velocity to determine whether there's any movement (if the hand isn't new)
|
||||
|
@ -180,14 +195,6 @@ void SixenseManager::update(float deltaTime) {
|
|||
if (numActiveControllers == 2) {
|
||||
updateCalibration(controllers);
|
||||
}
|
||||
|
||||
// if the controllers haven't been moved in a while, disable
|
||||
const unsigned int MOVEMENT_DISABLE_SECONDS = 3;
|
||||
if (usecTimestampNow() - _lastMovement > (MOVEMENT_DISABLE_SECONDS * USECS_PER_SECOND)) {
|
||||
for (std::vector<PalmData>::iterator it = hand->getPalms().begin(); it != hand->getPalms().end(); it++) {
|
||||
it->setActive(false);
|
||||
}
|
||||
}
|
||||
#endif // HAVE_SIXENSE
|
||||
}
|
||||
|
||||
|
|
|
@ -1701,6 +1701,13 @@ AnimationHandle::AnimationHandle(Model* model) :
|
|||
_running(false) {
|
||||
}
|
||||
|
||||
AnimationDetails AnimationHandle::getAnimationDetails() const {
|
||||
AnimationDetails details(_role, _url, _fps, _priority, _loop, _hold,
|
||||
_startAutomatically, _firstFrame, _lastFrame, _running, _frameIndex);
|
||||
return details;
|
||||
}
|
||||
|
||||
|
||||
void AnimationHandle::simulate(float deltaTime) {
|
||||
_frameIndex += deltaTime * _fps;
|
||||
|
||||
|
|
|
@ -354,6 +354,11 @@ public:
|
|||
void setRunning(bool running);
|
||||
bool isRunning() const { return _running; }
|
||||
|
||||
void setFrameIndex(float frameIndex) { _frameIndex = glm::clamp(_frameIndex, _firstFrame, _lastFrame); }
|
||||
float getFrameIndex() const { return _frameIndex; }
|
||||
|
||||
AnimationDetails getAnimationDetails() const;
|
||||
|
||||
signals:
|
||||
|
||||
void runningChanged(bool running);
|
||||
|
|
|
@ -102,3 +102,39 @@ void Animation::downloadFinished(QNetworkReply* reply) {
|
|||
QThreadPool::globalInstance()->start(new AnimationReader(_self, reply));
|
||||
}
|
||||
|
||||
|
||||
AnimationDetails::AnimationDetails() :
|
||||
role(), url(), fps(0.0f), priority(0.0f), loop(false), hold(false),
|
||||
startAutomatically(false), firstFrame(0.0f), lastFrame(0.0f), running(false), frameIndex(0.0f)
|
||||
{
|
||||
}
|
||||
|
||||
AnimationDetails::AnimationDetails(QString role, QUrl url, float fps, float priority, bool loop,
|
||||
bool hold, bool startAutomatically, float firstFrame, float lastFrame, bool running, float frameIndex) :
|
||||
role(role), url(url), fps(fps), priority(priority), loop(loop), hold(hold),
|
||||
startAutomatically(startAutomatically), firstFrame(firstFrame), lastFrame(lastFrame),
|
||||
running(running), frameIndex(frameIndex)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
QScriptValue animationDetailsToScriptValue(QScriptEngine* engine, const AnimationDetails& details) {
|
||||
QScriptValue obj = engine->newObject();
|
||||
obj.setProperty("role", details.role);
|
||||
obj.setProperty("url", details.url.toString());
|
||||
obj.setProperty("fps", details.fps);
|
||||
obj.setProperty("priority", details.priority);
|
||||
obj.setProperty("loop", details.loop);
|
||||
obj.setProperty("hold", details.hold);
|
||||
obj.setProperty("startAutomatically", details.startAutomatically);
|
||||
obj.setProperty("firstFrame", details.firstFrame);
|
||||
obj.setProperty("lastFrame", details.lastFrame);
|
||||
obj.setProperty("running", details.running);
|
||||
obj.setProperty("frameIndex", details.frameIndex);
|
||||
return obj;
|
||||
}
|
||||
|
||||
void animationDetailsFromScriptValue(const QScriptValue& object, AnimationDetails& details) {
|
||||
// nothing for now...
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +12,9 @@
|
|||
#ifndef hifi_AnimationCache_h
|
||||
#define hifi_AnimationCache_h
|
||||
|
||||
#include <QScriptEngine>
|
||||
#include <QScriptValue>
|
||||
|
||||
#include <ResourceCache.h>
|
||||
|
||||
#include <FBXReader.h>
|
||||
|
@ -68,4 +71,28 @@ private:
|
|||
bool _isValid;
|
||||
};
|
||||
|
||||
|
||||
class AnimationDetails {
|
||||
public:
|
||||
AnimationDetails();
|
||||
AnimationDetails(QString role, QUrl url, float fps, float priority, bool loop,
|
||||
bool hold, bool startAutomatically, float firstFrame, float lastFrame, bool running, float frameIndex);
|
||||
|
||||
QString role;
|
||||
QUrl url;
|
||||
float fps;
|
||||
float priority;
|
||||
bool loop;
|
||||
bool hold;
|
||||
bool startAutomatically;
|
||||
float firstFrame;
|
||||
float lastFrame;
|
||||
bool running;
|
||||
float frameIndex;
|
||||
};
|
||||
Q_DECLARE_METATYPE(AnimationDetails);
|
||||
QScriptValue animationDetailsToScriptValue(QScriptEngine* engine, const AnimationDetails& event);
|
||||
void animationDetailsFromScriptValue(const QScriptValue& object, AnimationDetails& event);
|
||||
|
||||
|
||||
#endif // hifi_AnimationCache_h
|
||||
|
|
|
@ -19,10 +19,11 @@
|
|||
#include "AudioRingBuffer.h"
|
||||
|
||||
|
||||
AudioRingBuffer::AudioRingBuffer(int numFrameSamples, bool randomAccessMode) :
|
||||
AudioRingBuffer::AudioRingBuffer(int numFrameSamples, bool randomAccessMode, int numFramesCapacity) :
|
||||
NodeData(),
|
||||
_overflowCount(0),
|
||||
_sampleCapacity(numFrameSamples * RING_BUFFER_LENGTH_FRAMES),
|
||||
_frameCapacity(numFramesCapacity),
|
||||
_sampleCapacity(numFrameSamples * numFramesCapacity),
|
||||
_isFull(false),
|
||||
_numFrameSamples(numFrameSamples),
|
||||
_isStarved(true),
|
||||
|
@ -48,6 +49,8 @@ AudioRingBuffer::~AudioRingBuffer() {
|
|||
}
|
||||
|
||||
void AudioRingBuffer::reset() {
|
||||
_overflowCount = 0;
|
||||
_isFull = false;
|
||||
_endOfLastWrite = _buffer;
|
||||
_nextOutput = _buffer;
|
||||
_isStarved = true;
|
||||
|
@ -55,13 +58,13 @@ void AudioRingBuffer::reset() {
|
|||
|
||||
void AudioRingBuffer::resizeForFrameSize(int numFrameSamples) {
|
||||
delete[] _buffer;
|
||||
_sampleCapacity = numFrameSamples * RING_BUFFER_LENGTH_FRAMES;
|
||||
_sampleCapacity = numFrameSamples * _frameCapacity;
|
||||
_numFrameSamples = numFrameSamples;
|
||||
_buffer = new int16_t[_sampleCapacity];
|
||||
if (_randomAccessMode) {
|
||||
memset(_buffer, 0, _sampleCapacity * sizeof(int16_t));
|
||||
}
|
||||
_nextOutput = _buffer;
|
||||
_endOfLastWrite = _buffer;
|
||||
reset();
|
||||
}
|
||||
|
||||
int AudioRingBuffer::parseData(const QByteArray& packet) {
|
||||
|
|
|
@ -31,15 +31,15 @@ const int NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL = NETWORK_BUFFER_LENGTH_BYTE
|
|||
const unsigned int BUFFER_SEND_INTERVAL_USECS = floorf((NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL
|
||||
/ (float) SAMPLE_RATE) * 1000 * 1000);
|
||||
|
||||
const short RING_BUFFER_LENGTH_FRAMES = 10;
|
||||
|
||||
const int MAX_SAMPLE_VALUE = std::numeric_limits<int16_t>::max();
|
||||
const int MIN_SAMPLE_VALUE = std::numeric_limits<int16_t>::min();
|
||||
|
||||
const int DEFAULT_RING_BUFFER_FRAME_CAPACITY = 10;
|
||||
|
||||
class AudioRingBuffer : public NodeData {
|
||||
Q_OBJECT
|
||||
public:
|
||||
AudioRingBuffer(int numFrameSamples, bool randomAccessMode = false);
|
||||
AudioRingBuffer(int numFrameSamples, bool randomAccessMode = false, int numFramesCapacity = DEFAULT_RING_BUFFER_FRAME_CAPACITY);
|
||||
~AudioRingBuffer();
|
||||
|
||||
void reset();
|
||||
|
@ -84,6 +84,7 @@ protected:
|
|||
|
||||
int _overflowCount; /// how many times has the ring buffer has overwritten old data
|
||||
|
||||
int _frameCapacity;
|
||||
int _sampleCapacity;
|
||||
bool _isFull;
|
||||
int _numFrameSamples;
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
#include "InjectedAudioRingBuffer.h"
|
||||
|
||||
InjectedAudioRingBuffer::InjectedAudioRingBuffer(const QUuid& streamIdentifier, bool dynamicJitterBuffer) :
|
||||
PositionalAudioRingBuffer(PositionalAudioRingBuffer::Injector, /* isStereo=*/ false , dynamicJitterBuffer),
|
||||
PositionalAudioRingBuffer(PositionalAudioRingBuffer::Injector, false, dynamicJitterBuffer),
|
||||
_streamIdentifier(streamIdentifier),
|
||||
_radius(0.0f),
|
||||
_attenuationRatio(0)
|
||||
|
|
|
@ -85,10 +85,10 @@ quint64 InterframeTimeGapStats::getWindowMaxGap() {
|
|||
}
|
||||
|
||||
|
||||
PositionalAudioRingBuffer::PositionalAudioRingBuffer(PositionalAudioRingBuffer::Type type,
|
||||
bool isStereo, bool dynamicJitterBuffers) :
|
||||
PositionalAudioRingBuffer::PositionalAudioRingBuffer(PositionalAudioRingBuffer::Type type, bool isStereo, bool dynamicJitterBuffers) :
|
||||
|
||||
AudioRingBuffer(isStereo ? NETWORK_BUFFER_LENGTH_SAMPLES_STEREO : NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL),
|
||||
AudioRingBuffer(isStereo ? NETWORK_BUFFER_LENGTH_SAMPLES_STEREO : NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL,
|
||||
false, AUDIOMIXER_INBOUND_RING_BUFFER_FRAME_CAPACITY),
|
||||
_type(type),
|
||||
_position(0.0f, 0.0f, 0.0f),
|
||||
_orientation(0.0f, 0.0f, 0.0f, 0.0f),
|
||||
|
@ -98,7 +98,7 @@ PositionalAudioRingBuffer::PositionalAudioRingBuffer(PositionalAudioRingBuffer::
|
|||
_isStereo(isStereo),
|
||||
_listenerUnattenuatedZone(NULL),
|
||||
_desiredJitterBufferFrames(1),
|
||||
_currentJitterBufferFrames(0),
|
||||
_currentJitterBufferFrames(-1),
|
||||
_dynamicJitterBuffers(dynamicJitterBuffers)
|
||||
{
|
||||
}
|
||||
|
@ -216,8 +216,8 @@ bool PositionalAudioRingBuffer::shouldBeAddedToMix() {
|
|||
// if the buffer doesn't have a full frame of samples to take for mixing, it is starved
|
||||
_isStarved = true;
|
||||
|
||||
// set to 0 to indicate the jitter buffer is starved
|
||||
_currentJitterBufferFrames = 0;
|
||||
// set to -1 to indicate the jitter buffer is starved
|
||||
_currentJitterBufferFrames = -1;
|
||||
|
||||
// reset our _shouldOutputStarveDebug to true so the next is printed
|
||||
_shouldOutputStarveDebug = true;
|
||||
|
@ -261,7 +261,7 @@ void PositionalAudioRingBuffer::updateDesiredJitterBufferFrames() {
|
|||
if (_desiredJitterBufferFrames < 1) {
|
||||
_desiredJitterBufferFrames = 1;
|
||||
}
|
||||
const int maxDesired = RING_BUFFER_LENGTH_FRAMES - 1;
|
||||
const int maxDesired = _frameCapacity - 1;
|
||||
if (_desiredJitterBufferFrames > maxDesired) {
|
||||
_desiredJitterBufferFrames = maxDesired;
|
||||
}
|
||||
|
|
|
@ -43,6 +43,8 @@ private:
|
|||
bool _newWindowMaxGapAvailable;
|
||||
};
|
||||
|
||||
const int AUDIOMIXER_INBOUND_RING_BUFFER_FRAME_CAPACITY = 100;
|
||||
|
||||
class PositionalAudioRingBuffer : public AudioRingBuffer {
|
||||
public:
|
||||
enum Type {
|
||||
|
@ -103,6 +105,11 @@ protected:
|
|||
int _desiredJitterBufferFrames;
|
||||
int _currentJitterBufferFrames;
|
||||
bool _dynamicJitterBuffers;
|
||||
|
||||
// extra stats
|
||||
int _starveCount;
|
||||
int _silentFramesDropped;
|
||||
|
||||
};
|
||||
|
||||
#endif // hifi_PositionalAudioRingBuffer_h
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
//
|
||||
|
||||
#include <QMetaObject>
|
||||
#include <QAbstractNetworkCache>
|
||||
#include <QThread>
|
||||
|
||||
#include "NetworkAccessManager.h"
|
||||
|
@ -20,6 +21,7 @@ NetworkAccessManager& NetworkAccessManager::getInstance() {
|
|||
}
|
||||
|
||||
NetworkAccessManager::NetworkAccessManager() {
|
||||
qRegisterMetaType<QAbstractNetworkCache*>();
|
||||
}
|
||||
|
||||
QNetworkReply* NetworkAccessManager::get(const QNetworkRequest& request) {
|
||||
|
@ -146,4 +148,14 @@ QNetworkReply* NetworkAccessManager::sendCustomRequest(const QNetworkRequest& re
|
|||
return result;
|
||||
}
|
||||
return QNetworkAccessManager::sendCustomRequest(request, verb, data);
|
||||
}
|
||||
|
||||
void NetworkAccessManager::setCache(QAbstractNetworkCache* cache) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QMetaObject::invokeMethod(this,
|
||||
"setCache",
|
||||
Qt::BlockingQueuedConnection,
|
||||
Q_ARG(QAbstractNetworkCache*, cache));
|
||||
}
|
||||
QNetworkAccessManager::setCache(cache);
|
||||
}
|
|
@ -18,7 +18,9 @@
|
|||
|
||||
/// Wrapper around QNetworkAccessManager wo that we only use one instance
|
||||
/// For any other method you should need, make sure to be on the right thread
|
||||
/// or call the method using QMetaObject::invokeMethod()
|
||||
/// or if it is not but is a slot, use QMetaObject::invokeMethod()
|
||||
/// In the case what you want to call isn't a slot and you aren't on the same thread,
|
||||
/// then add then method to the method to the wrapper with the Q_INVKABLE flag
|
||||
class NetworkAccessManager : public QNetworkAccessManager {
|
||||
Q_OBJECT
|
||||
public:
|
||||
|
@ -33,6 +35,7 @@ public:
|
|||
Q_INVOKABLE QNetworkReply* put(const QNetworkRequest& request, QHttpMultiPart* multiPart);
|
||||
Q_INVOKABLE QNetworkReply* put(const QNetworkRequest& request, const QByteArray& data);
|
||||
Q_INVOKABLE QNetworkReply* sendCustomRequest(const QNetworkRequest& request, const QByteArray& verb, QIODevice* data = 0);
|
||||
Q_INVOKABLE void setCache(QAbstractNetworkCache* cache);
|
||||
|
||||
private:
|
||||
NetworkAccessManager();
|
||||
|
|
|
@ -15,10 +15,12 @@
|
|||
#include <qbytearray.h>
|
||||
#include <qvector.h>
|
||||
|
||||
#include "SequenceNumberStats.h"
|
||||
|
||||
class SentPacketHistory {
|
||||
|
||||
public:
|
||||
SentPacketHistory(int size = 1000);
|
||||
SentPacketHistory(int size = MAX_REASONABLE_SEQUENCE_GAP);
|
||||
|
||||
void packetSent(uint16_t sequenceNumber, const QByteArray& packet);
|
||||
const QByteArray* getPacket(uint16_t sequenceNumber) const;
|
||||
|
|
|
@ -39,7 +39,6 @@ void SequenceNumberStats::reset() {
|
|||
}
|
||||
|
||||
static const int UINT16_RANGE = std::numeric_limits<uint16_t>::max() + 1;
|
||||
static const int MAX_REASONABLE_SEQUENCE_GAP = 1000; // this must be less than UINT16_RANGE / 2 for rollover handling to work
|
||||
|
||||
void SequenceNumberStats::sequenceNumberReceived(quint16 incoming, QUuid senderUUID, const bool wantExtraDebugging) {
|
||||
|
||||
|
@ -95,6 +94,7 @@ void SequenceNumberStats::sequenceNumberReceived(quint16 incoming, QUuid senderU
|
|||
|
||||
_numEarly++;
|
||||
_numLost += (incomingInt - expectedInt);
|
||||
_lastReceived = incoming;
|
||||
|
||||
// add all sequence numbers that were skipped to the missing sequence numbers list
|
||||
for (int missingInt = expectedInt; missingInt < incomingInt; missingInt++) {
|
||||
|
@ -106,14 +106,14 @@ void SequenceNumberStats::sequenceNumberReceived(quint16 incoming, QUuid senderU
|
|||
if (_missingSet.size() > MAX_REASONABLE_SEQUENCE_GAP) {
|
||||
pruneMissingSet(wantExtraDebugging);
|
||||
}
|
||||
|
||||
_lastReceived = incoming;
|
||||
} else { // late
|
||||
if (wantExtraDebugging) {
|
||||
qDebug() << "this packet is later than expected...";
|
||||
}
|
||||
_numLate++;
|
||||
|
||||
// do not update _lastReceived; it shouldn't become smaller
|
||||
|
||||
// remove this from missing sequence number if it's in there
|
||||
if (_missingSet.remove(incoming)) {
|
||||
if (wantExtraDebugging) {
|
||||
|
@ -127,8 +127,6 @@ void SequenceNumberStats::sequenceNumberReceived(quint16 incoming, QUuid senderU
|
|||
}
|
||||
_numDuplicate++;
|
||||
}
|
||||
|
||||
// do not update _incomingLastSequence; it shouldn't become smaller
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,13 +15,15 @@
|
|||
#include "SharedUtil.h"
|
||||
#include <quuid.h>
|
||||
|
||||
const int MAX_REASONABLE_SEQUENCE_GAP = 1000;
|
||||
|
||||
class SequenceNumberStats {
|
||||
public:
|
||||
SequenceNumberStats();
|
||||
|
||||
void reset();
|
||||
|
||||
void sequenceNumberReceived(quint16 incoming, QUuid senderUUID = QUuid(), const bool wantExtraDebugging = false);
|
||||
void pruneMissingSet(const bool wantExtraDebugging = false);
|
||||
|
||||
quint32 getNumReceived() const { return _numReceived; }
|
||||
quint32 getNumUnreasonable() const { return _numUnreasonable; }
|
||||
|
@ -34,8 +36,6 @@ public:
|
|||
const QSet<quint16>& getMissingSet() const { return _missingSet; }
|
||||
|
||||
private:
|
||||
void pruneMissingSet(const bool wantExtraDebugging);
|
||||
|
||||
quint16 _lastReceived;
|
||||
QSet<quint16> _missingSet;
|
||||
|
||||
|
|
|
@ -168,6 +168,7 @@ public:
|
|||
float getIncomingFlightTimeAverage() { return _incomingFlightTimeAverage.getAverage(); }
|
||||
|
||||
const SequenceNumberStats& getIncomingOctreeSequenceNumberStats() const { return _incomingOctreeSequenceNumberStats; }
|
||||
SequenceNumberStats& getIncomingOctreeSequenceNumberStats() { return _incomingOctreeSequenceNumberStats; }
|
||||
|
||||
private:
|
||||
|
||||
|
|
37
libraries/script-engine/src/MIDIEvent.cpp
Normal file
37
libraries/script-engine/src/MIDIEvent.cpp
Normal file
|
@ -0,0 +1,37 @@
|
|||
//
|
||||
// MIDIEvent.cpp
|
||||
// libraries/script-engine/src
|
||||
//
|
||||
// Created by Stephen Birarda on 2014-06-30.
|
||||
// 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
|
||||
//
|
||||
|
||||
#include "MIDIEvent.h"
|
||||
|
||||
void registerMIDIMetaTypes(QScriptEngine* engine) {
|
||||
qScriptRegisterMetaType(engine, midiEventToScriptValue, midiEventFromScriptValue);
|
||||
}
|
||||
|
||||
const QString MIDI_DELTA_TIME_PROP_NAME = "deltaTime";
|
||||
const QString MIDI_EVENT_TYPE_PROP_NAME = "type";
|
||||
const QString MIDI_DATA_1_PROP_NAME = "data1";
|
||||
const QString MIDI_DATA_2_PROP_NAME = "data2";
|
||||
|
||||
QScriptValue midiEventToScriptValue(QScriptEngine* engine, const MIDIEvent& event) {
|
||||
QScriptValue obj = engine->newObject();
|
||||
obj.setProperty(MIDI_DELTA_TIME_PROP_NAME, event.deltaTime);
|
||||
obj.setProperty(MIDI_EVENT_TYPE_PROP_NAME, event.type);
|
||||
obj.setProperty(MIDI_DATA_1_PROP_NAME, event.data1);
|
||||
obj.setProperty(MIDI_DATA_2_PROP_NAME, event.data2);
|
||||
return obj;
|
||||
}
|
||||
|
||||
void midiEventFromScriptValue(const QScriptValue &object, MIDIEvent& event) {
|
||||
event.deltaTime = object.property(MIDI_DELTA_TIME_PROP_NAME).toVariant().toDouble();
|
||||
event.type = object.property(MIDI_EVENT_TYPE_PROP_NAME).toVariant().toUInt();
|
||||
event.data1 = object.property(MIDI_DATA_1_PROP_NAME).toVariant().toUInt();
|
||||
event.data2 = object.property(MIDI_DATA_2_PROP_NAME).toVariant().toUInt();
|
||||
}
|
32
libraries/script-engine/src/MIDIEvent.h
Normal file
32
libraries/script-engine/src/MIDIEvent.h
Normal file
|
@ -0,0 +1,32 @@
|
|||
//
|
||||
// MIDIEvent.h
|
||||
// libraries/script-engine/src
|
||||
//
|
||||
// Created by Stephen Birarda on 2014-06-30.
|
||||
// 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
|
||||
//
|
||||
|
||||
#include <QtScript/QScriptEngine>
|
||||
|
||||
#ifndef hifi_MIDIEvent_h
|
||||
#define hifi_MIDIEvent_h
|
||||
|
||||
class MIDIEvent {
|
||||
public:
|
||||
double deltaTime;
|
||||
unsigned int type;
|
||||
unsigned int data1;
|
||||
unsigned int data2;
|
||||
};
|
||||
|
||||
Q_DECLARE_METATYPE(MIDIEvent)
|
||||
|
||||
void registerMIDIMetaTypes(QScriptEngine* engine);
|
||||
|
||||
QScriptValue midiEventToScriptValue(QScriptEngine* engine, const MIDIEvent& event);
|
||||
void midiEventFromScriptValue(const QScriptValue &object, MIDIEvent& event);
|
||||
|
||||
#endif // hifi_MIDIEvent_h
|
|
@ -33,6 +33,7 @@
|
|||
|
||||
#include "AnimationObject.h"
|
||||
#include "MenuItemProperties.h"
|
||||
#include "MIDIEvent.h"
|
||||
#include "LocalVoxels.h"
|
||||
#include "ScriptEngine.h"
|
||||
#include "XMLHttpRequestClass.h"
|
||||
|
@ -217,6 +218,7 @@ void ScriptEngine::init() {
|
|||
|
||||
// register various meta-types
|
||||
registerMetaTypes(&_engine);
|
||||
registerMIDIMetaTypes(&_engine);
|
||||
registerVoxelMetaTypes(&_engine);
|
||||
registerEventTypes(&_engine);
|
||||
registerMenuItemProperties(&_engine);
|
||||
|
@ -254,6 +256,8 @@ void ScriptEngine::init() {
|
|||
|
||||
qScriptRegisterMetaType(&_engine, injectorToScriptValue, injectorFromScriptValue);
|
||||
|
||||
qScriptRegisterMetaType(&_engine, animationDetailsToScriptValue, animationDetailsFromScriptValue);
|
||||
|
||||
registerGlobalObject("Script", this);
|
||||
registerGlobalObject("Audio", &_audioScriptingInterface);
|
||||
registerGlobalObject("Controller", _controllerScriptingInterface);
|
||||
|
|
|
@ -29,7 +29,7 @@ void AudioRingBufferTests::runAllTests() {
|
|||
int readIndexAt;
|
||||
|
||||
|
||||
AudioRingBuffer ringBuffer(10); // makes buffer of 100 int16_t samples
|
||||
AudioRingBuffer ringBuffer(10, false, 10); // makes buffer of 100 int16_t samples
|
||||
for (int T = 0; T < 300; T++) {
|
||||
|
||||
writeIndexAt = 0;
|
||||
|
|
|
@ -115,6 +115,11 @@ void SequenceNumberStatsTests::earlyLateTest() {
|
|||
}
|
||||
}
|
||||
stats.reset();
|
||||
numSent = 0;
|
||||
numEarly = 0;
|
||||
numLate = 0;
|
||||
numLost = 0;
|
||||
numRecovered = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -203,6 +208,11 @@ void SequenceNumberStatsTests::duplicateTest() {
|
|||
}
|
||||
}
|
||||
stats.reset();
|
||||
numSent = 0;
|
||||
numDuplicate = 0;
|
||||
numEarly = 0;
|
||||
numLate = 0;
|
||||
numLost = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -263,5 +273,8 @@ void SequenceNumberStatsTests::pruneTest() {
|
|||
}
|
||||
}
|
||||
stats.reset();
|
||||
numSent = 0;
|
||||
numEarly = 0;
|
||||
numLost = 0;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue