Merge branch 'master' of https://github.com/highfidelity/hifi into metavoxels

This commit is contained in:
Andrzej Kapolka 2014-07-08 16:49:14 -07:00
commit 2dbe72a818
24 changed files with 321 additions and 118 deletions

View file

@ -32,14 +32,6 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON)
# Instruct CMake to run moc automatically when needed. # Instruct CMake to run moc automatically when needed.
set(CMAKE_AUTOMOC ON) set(CMAKE_AUTOMOC ON)
if (APPLE)
exec_program(uname ARGS -v OUTPUT_VARIABLE DARWIN_VERSION)
string(REGEX MATCH "[0-9]+" DARWIN_VERSION ${DARWIN_VERSION})
if (DARWIN_VERSION GREATER 12)
set(CMAKE_CXX_FLAGS "-stdlib=libstdc++")
endif (DARWIN_VERSION GREATER 12)
endif (APPLE)
# targets not supported on windows # targets not supported on windows
if (NOT WIN32) if (NOT WIN32)
add_subdirectory(animation-server) add_subdirectory(animation-server)

View file

@ -138,11 +138,14 @@ void AudioMixerClientData::pushBuffersAfterFrameSend() {
// this was a used buffer, push the output pointer forwards // this was a used buffer, push the output pointer forwards
PositionalAudioRingBuffer* audioBuffer = *i; PositionalAudioRingBuffer* audioBuffer = *i;
const int INJECTOR_CONSECUTIVE_NOT_MIXED_THRESHOLD = 100;
if (audioBuffer->willBeAddedToMix()) { if (audioBuffer->willBeAddedToMix()) {
audioBuffer->shiftReadPosition(audioBuffer->getSamplesPerFrame()); audioBuffer->shiftReadPosition(audioBuffer->getSamplesPerFrame());
audioBuffer->setWillBeAddedToMix(false); audioBuffer->setWillBeAddedToMix(false);
} else if (audioBuffer->getType() == PositionalAudioRingBuffer::Injector } else if (audioBuffer->getType() == PositionalAudioRingBuffer::Injector
&& audioBuffer->hasStarted() && audioBuffer->isStarved()) { && audioBuffer->hasStarted() && audioBuffer->isStarved()
&& audioBuffer->getConsecutiveNotMixedCount() > INJECTOR_CONSECUTIVE_NOT_MIXED_THRESHOLD) {
// this is an empty audio buffer that has starved, safe to delete // this is an empty audio buffer that has starved, safe to delete
// also delete its sequence number stats // also delete its sequence number stats
QUuid streamIdentifier = ((InjectedAudioRingBuffer*)audioBuffer)->getStreamIdentifier(); QUuid streamIdentifier = ((InjectedAudioRingBuffer*)audioBuffer)->getStreamIdentifier();

View file

@ -26,8 +26,8 @@ else ()
set(RTMIDI_SEARCH_DIRS "${RTMIDI_ROOT_DIR}" "$ENV{HIFI_LIB_DIR}/rtmidi") 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_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}) find_library(RTMIDI_LIBRARY NAMES rtmidi PATH_SUFFIXES lib HINTS ${RTMIDI_SEARCH_DIRS})
include(FindPackageHandleStandardArgs) include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(RTMIDI DEFAULT_MSG RTMIDI_INCLUDE_DIR RTMIDI_CPP) find_package_handle_standard_args(RTMIDI DEFAULT_MSG RTMIDI_INCLUDE_DIR RTMIDI_LIBRARY)
endif () endif ()

View file

@ -10,27 +10,34 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
// //
function length(v) { var clapAnimation = "https://s3-us-west-1.amazonaws.com/highfidelity-public/animations/ClapAnimations/ClapHands_Standing.fbx";
return Math.sqrt(v.x * v.x + v.y * v.y + v.z * v.z); var startEndFrames = [];
} startEndFrames.push({ start: 0, end: 8});
startEndFrames.push({ start: 10, end: 20});
startEndFrames.push({ start: 20, end: 28});
startEndFrames.push({ start: 30, end: 37});
startEndFrames.push({ start: 41, end: 46});
startEndFrames.push({ start: 53, end: 58});
var lastClapFrame = 0;
var lastAnimFrame = 0;
function printVector(v) { var claps = [];
print(v.x + ", " + v.y + ", " + v.z + "\n"); claps.push(new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/claps/Clap1Reverb.wav"));
} claps.push(new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/claps/Clap2Reverb.wav"));
claps.push(new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/claps/Clap3Reverb.wav"));
claps.push(new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/claps/Clap4Reverb.wav"));
claps.push(new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/claps/Clap5Reverb.wav"));
claps.push(new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/claps/Clap6Reverb.wav"));
var numberOfSounds = claps.length;
function vMinus(a, b) { var clappingNow = false;
var rval = { x: a.x - b.x, y: a.y - b.y, z: a.z - b.z }; var collectedClicks = 0;
return rval;
}
// First, load the clap sound from a URL var clickClappingNow = false;
var clap1 = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/claps/clap1.raw"); var CLAP_START_RATE = 15.0;
var clap2 = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/claps/clap2.raw"); var clapRate = CLAP_START_RATE;
var clap3 = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/claps/clap3.raw"); var startedTimer = false;
var clap4 = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/claps/clap4.raw");
var clap5 = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/claps/clap5.raw");
var clap6 = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/claps/clap6.raw");
var clapping = new Array(); var clapping = new Array();
clapping[0] = false; clapping[0] = false;
@ -38,36 +45,94 @@ clapping[1] = false;
function maybePlaySound(deltaTime) { function maybePlaySound(deltaTime) {
// Set the location and other info for the sound to play // Set the location and other info for the sound to play
var palm1Position = Controller.getSpatialControlPosition(0);
var palm2Position = Controller.getSpatialControlPosition(2);
var distanceBetween = length(vMinus(palm1Position, palm2Position));
for (var palm = 0; palm < 2; palm++) { var animationDetails = MyAvatar.getAnimationDetails(clapAnimation);
var palmVelocity = Controller.getSpatialControlVelocity(palm * 2 + 1);
var speed = length(palmVelocity);
const CLAP_SPEED = 0.2;
const CLAP_DISTANCE = 0.2;
if (!clapping[palm] && (distanceBetween < CLAP_DISTANCE) && (speed > CLAP_SPEED)) { var frame = Math.floor(animationDetails.frameIndex);
var options = new AudioInjectionOptions();
options.position = palm1Position; if (frame != lastAnimFrame) {
options.volume = speed / 2.0; print("frame " + frame);
if (options.volume > 1.0) options.volume = 1.0; lastAnimFrame = frame;
which = Math.floor((Math.random() * 6) + 1); }
if (which == 1) { Audio.playSound(clap1, options); } for (var i = 0; i < startEndFrames.length; i++) {
else if (which == 2) { Audio.playSound(clap2, options); } if (frame == startEndFrames[i].start && (frame != lastClapFrame)) {
else if (which == 3) { Audio.playSound(clap3, options); } playClap(1.0, Camera.getPosition());
else if (which == 4) { Audio.playSound(clap4, options); } lastClapFrame = frame;
else if (which == 5) { Audio.playSound(clap5, options); } }
else { Audio.playSound(clap6, options); } }
Audio.playSound(clap, options);
clapping[palm] = true; var palm1Position = MyAvatar.getLeftPalmPosition();
} else if (clapping[palm] && (speed < (CLAP_SPEED / 4.0))) { var palm2Position = MyAvatar.getRightPalmPosition();
clapping[palm] = false; var distanceBetween = Vec3.length(Vec3.subtract(palm1Position, palm2Position));
}
var palm1Velocity = Controller.getSpatialControlVelocity(1);
var palm2Velocity = Controller.getSpatialControlVelocity(3);
var closingVelocity = Vec3.length(Vec3.subtract(palm1Velocity, palm2Velocity));
const CLAP_SPEED = 0.7;
const CLAP_DISTANCE = 0.15;
if ((closingVelocity > CLAP_SPEED) && (distanceBetween < CLAP_DISTANCE) && !clappingNow) {
var volume = closingVelocity / 2.0;
if (volume > 1.0) volume = 1.0;
playClap(volume, palm1Position);
clappingNow = true;
} else if (clappingNow && (distanceBetween > CLAP_DISTANCE * 1.2)) {
clappingNow = false;
} }
} }
function playClap(volume, position) {
var options = new AudioInjectionOptions();
options.position = position;
options.volume = 1.0;
var clip = Math.floor(Math.random() * numberOfSounds);
Audio.playSound(claps[clip], options);
}
function keepClapping() {
playClap(1.0, Camera.getPosition());
}
Controller.keyPressEvent.connect(function(event) {
if(event.text == "SHIFT") {
if (!clickClappingNow) {
playClap(1.0, Camera.getPosition());
var whichClip = Math.floor(Math.random() * startEndFrames.length);
lastClapFrame = 0;
MyAvatar.startAnimation(clapAnimation, clapRate, 1.0, true, false);
clickClappingNow = true;
} else {
clapRate *= 1.25;
MyAvatar.stopAnimation(clapAnimation);
MyAvatar.startAnimation(clapAnimation, clapRate, 1.0, true, false);
collectedClicks = collectedClicks + 1;
}
}
});
var CLAP_END_WAIT_MSECS = 500;
Controller.keyReleaseEvent.connect(function(event) {
if (event.text == "SHIFT") {
if (!startedTimer) {
startedTimer = true;
collectedClicks = 0;
Script.setTimeout(stopClapping, CLAP_END_WAIT_MSECS);
}
}
});
function stopClapping() {
if (collectedClicks == 0) {
startedTimer = false;
MyAvatar.stopAnimation(clapAnimation);
clapRate = CLAP_START_RATE;
clickClappingNow = false;
} else {
startedTimer = false;
}
}
// Connect a call back that happens every frame // Connect a call back that happens every frame
Script.update.connect(maybePlaySound); Script.update.connect(maybePlaySound);
//Controller.keyPressEvent.connect(keyPressEvent);

View file

@ -57,7 +57,7 @@ var LocationMenu = function(opts) {
y: 0, y: 0,
width: menuWidth + 10, width: menuWidth + 10,
height: (menuHeight * (pageSize + 1)) + 10, height: (menuHeight * (pageSize + 1)) + 10,
color: { red: 0, green: 0, blue: 0}, backgroundColor: { red: 0, green: 0, blue: 0},
topMargin: 4, topMargin: 4,
leftMargin: 4, leftMargin: 4,
text: "", text: "",
@ -71,7 +71,7 @@ var LocationMenu = function(opts) {
y: 0, y: 0,
width: menuWidth, width: menuWidth,
height: menuHeight, height: menuHeight,
color: inactiveColor, backgroundColor: inactiveColor,
topMargin: margin, topMargin: margin,
leftMargin: margin, leftMargin: margin,
text: (i == 0) ? "Loading..." : "", text: (i == 0) ? "Loading..." : "",
@ -85,7 +85,7 @@ var LocationMenu = function(opts) {
y: 0, y: 0,
width: menuWidth / 2, width: menuWidth / 2,
height: menuHeight, height: menuHeight,
color: disabledColor, backgroundColor: disabledColor,
topMargin: margin, topMargin: margin,
leftMargin: margin, leftMargin: margin,
text: "Previous", text: "Previous",
@ -97,7 +97,7 @@ var LocationMenu = function(opts) {
y: 0, y: 0,
width: menuWidth / 2, width: menuWidth / 2,
height: menuHeight, height: menuHeight,
color: disabledColor, backgroundColor: disabledColor,
topMargin: margin, topMargin: margin,
leftMargin: margin, leftMargin: margin,
text: "Next", text: "Next",
@ -175,10 +175,10 @@ var LocationMenu = function(opts) {
if (start + i < this.locations.length) { if (start + i < this.locations.length) {
location = this.locations[start + i]; location = this.locations[start + i];
update.text = (start + i + 1) + ". " + location.username; update.text = (start + i + 1) + ". " + location.username;
update.color = inactiveColor; update.backgroundColor = inactiveColor;
} else { } else {
update.text = ""; update.text = "";
update.color = disabledColor; update.backgroundColor = disabledColor;
} }
Overlays.editOverlay(this.menuItems[i].overlay, update); Overlays.editOverlay(this.menuItems[i].overlay, update);
this.menuItems[i].location = location; this.menuItems[i].location = location;
@ -187,8 +187,8 @@ var LocationMenu = function(opts) {
this.previousEnabled = pageNumber > 0; this.previousEnabled = pageNumber > 0;
this.nextEnabled = pageNumber < (this.numPages - 1); this.nextEnabled = pageNumber < (this.numPages - 1);
Overlays.editOverlay(this.previousButton, { color: this.previousEnabled ? prevNextColor : disabledColor}); Overlays.editOverlay(this.previousButton, { backgroundColor: this.previousEnabled ? prevNextColor : disabledColor});
Overlays.editOverlay(this.nextButton, { color: this.nextEnabled ? prevNextColor : disabledColor }); Overlays.editOverlay(this.nextButton, { backgroundColor: this.nextEnabled ? prevNextColor : disabledColor });
} }
this.mousePressEvent = function(event) { this.mousePressEvent = function(event) {
@ -198,17 +198,17 @@ var LocationMenu = function(opts) {
self.toggleMenu(); self.toggleMenu();
} else if (clickedOverlay == self.previousButton) { } else if (clickedOverlay == self.previousButton) {
if (self.previousEnabled) { if (self.previousEnabled) {
Overlays.editOverlay(clickedOverlay, { color: activeColor }); Overlays.editOverlay(clickedOverlay, { backgroundColor: activeColor });
} }
} else if (clickedOverlay == self.nextButton) { } else if (clickedOverlay == self.nextButton) {
if (self.nextEnabled) { if (self.nextEnabled) {
Overlays.editOverlay(clickedOverlay, { color: activeColor }); Overlays.editOverlay(clickedOverlay, { backgroundColor: activeColor });
} }
} else { } else {
for (var i = 0; i < self.menuItems.length; i++) { for (var i = 0; i < self.menuItems.length; i++) {
if (clickedOverlay == self.menuItems[i].overlay) { if (clickedOverlay == self.menuItems[i].overlay) {
if (self.menuItems[i].location != null) { if (self.menuItems[i].location != null) {
Overlays.editOverlay(clickedOverlay, { color: activeColor }); Overlays.editOverlay(clickedOverlay, { backgroundColor: activeColor });
} }
break; break;
} }
@ -221,19 +221,19 @@ var LocationMenu = function(opts) {
if (clickedOverlay == self.previousButton) { if (clickedOverlay == self.previousButton) {
if (self.previousEnabled) { if (self.previousEnabled) {
Overlays.editOverlay(clickedOverlay, { color: inactiveColor }); Overlays.editOverlay(clickedOverlay, { backgroundColor: inactiveColor });
self.goToPage(self.page - 1); self.goToPage(self.page - 1);
} }
} else if (clickedOverlay == self.nextButton) { } else if (clickedOverlay == self.nextButton) {
if (self.nextEnabled) { if (self.nextEnabled) {
Overlays.editOverlay(clickedOverlay, { color: inactiveColor }); Overlays.editOverlay(clickedOverlay, { backgroundColor: inactiveColor });
self.goToPage(self.page + 1); self.goToPage(self.page + 1);
} }
} else { } else {
for (var i = 0; i < self.menuItems.length; i++) { for (var i = 0; i < self.menuItems.length; i++) {
if (clickedOverlay == self.menuItems[i].overlay) { if (clickedOverlay == self.menuItems[i].overlay) {
if (self.menuItems[i].location != null) { if (self.menuItems[i].location != null) {
Overlays.editOverlay(clickedOverlay, { color: inactiveColor }); Overlays.editOverlay(clickedOverlay, { backgroundColor: inactiveColor });
var location = self.menuItems[i].location; var location = self.menuItems[i].location;
Window.location = "hifi://" + location.domain + "/" Window.location = "hifi://" + location.domain + "/"
+ location.x + "," + location.y + "," + location.z; + location.x + "," + location.y + "," + location.z;

View file

@ -18,13 +18,16 @@ var RIGHT = 1;
var lastLeftFrame = 0; var lastLeftFrame = 0;
var lastRightFrame = 0; var lastRightFrame = 0;
var LAST_FRAME = 11.0; // What is the number of the last frame we want to use in the animation? var leftDirection = true;
var SMOOTH_FACTOR = 0.80; var rightDirection = true;
var LAST_FRAME = 15.0; // What is the number of the last frame we want to use in the animation?
var SMOOTH_FACTOR = 0.0;
var MAX_FRAMES = 30.0;
Script.update.connect(function(deltaTime) { Script.update.connect(function(deltaTime) {
var leftTriggerValue = Math.sqrt(Controller.getTriggerValue(LEFT)); var leftTriggerValue = Controller.getTriggerValue(LEFT);
var rightTriggerValue = Math.sqrt(Controller.getTriggerValue(RIGHT)); var rightTriggerValue = Controller.getTriggerValue(RIGHT);
var leftFrame, rightFrame; var leftFrame, rightFrame;
@ -32,10 +35,31 @@ Script.update.connect(function(deltaTime) {
leftFrame = (leftTriggerValue * LAST_FRAME) * (1.0 - SMOOTH_FACTOR) + lastLeftFrame * SMOOTH_FACTOR; leftFrame = (leftTriggerValue * LAST_FRAME) * (1.0 - SMOOTH_FACTOR) + lastLeftFrame * SMOOTH_FACTOR;
rightFrame = (rightTriggerValue * LAST_FRAME) * (1.0 - SMOOTH_FACTOR) + lastRightFrame * SMOOTH_FACTOR; rightFrame = (rightTriggerValue * LAST_FRAME) * (1.0 - SMOOTH_FACTOR) + lastRightFrame * SMOOTH_FACTOR;
if (!leftDirection) {
leftFrame = MAX_FRAMES - leftFrame;
}
if (!rightDirection) {
rightFrame = MAX_FRAMES - rightFrame;
}
if ((leftTriggerValue == 1.0) && (leftDirection == true)) {
leftDirection = false;
lastLeftFrame = MAX_FRAMES - leftFrame;
} else if ((leftTriggerValue == 0.0) && (leftDirection == false)) {
leftDirection = true;
lastLeftFrame = leftFrame;
}
if ((rightTriggerValue == 1.0) && (rightDirection == true)) {
rightDirection = false;
lastRightFrame = MAX_FRAMES - rightFrame;
} else if ((rightTriggerValue == 0.0) && (rightDirection == false)) {
rightDirection = true;
lastRightFrame = rightFrame;
}
if ((leftFrame != lastLeftFrame) && leftHandAnimation.length){ if ((leftFrame != lastLeftFrame) && leftHandAnimation.length){
MyAvatar.stopAnimation(leftHandAnimation); MyAvatar.stopAnimation(leftHandAnimation);
MyAvatar.startAnimation(leftHandAnimation, 30.0, 1.0, false, true, leftFrame, leftFrame); MyAvatar.startAnimation(leftHandAnimation, 30.0, 1.0, false, true, leftFrame, leftFrame);
} }
if ((rightFrame != lastRightFrame) && rightHandAnimation.length) { if ((rightFrame != lastRightFrame) && rightHandAnimation.length) {
MyAvatar.stopAnimation(rightHandAnimation); MyAvatar.stopAnimation(rightHandAnimation);

View file

@ -111,16 +111,6 @@ if (APPLE)
SET(INTERFACE_SRCS ${INTERFACE_SRCS} "${CMAKE_CURRENT_SOURCE_DIR}/interface.icns") SET(INTERFACE_SRCS ${INTERFACE_SRCS} "${CMAKE_CURRENT_SOURCE_DIR}/interface.icns")
endif() 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 # create the executable, make it a bundle on OS X
add_executable(${TARGET_NAME} MACOSX_BUNDLE ${INTERFACE_SRCS} ${QM}) add_executable(${TARGET_NAME} MACOSX_BUNDLE ${INTERFACE_SRCS} ${QM})
@ -151,6 +141,7 @@ find_package(Sixense)
find_package(Visage) find_package(Visage)
find_package(ZLIB) find_package(ZLIB)
find_package(Qxmpp) find_package(Qxmpp)
find_package(RtMidi)
# include the Sixense library for Razer Hydra if available # include the Sixense library for Razer Hydra if available
if (SIXENSE_FOUND AND NOT DISABLE_SIXENSE) if (SIXENSE_FOUND AND NOT DISABLE_SIXENSE)
@ -223,11 +214,18 @@ if (QXMPP_FOUND AND NOT DISABLE_QXMPP)
target_link_libraries(${TARGET_NAME} "${QXMPP_LIBRARY}") target_link_libraries(${TARGET_NAME} "${QXMPP_LIBRARY}")
endif (QXMPP_FOUND AND NOT DISABLE_QXMPP) endif (QXMPP_FOUND AND NOT DISABLE_QXMPP)
# link CoreMIDI if we're using RtMidi # and with RtMidi for RtMidi control
if (RTMIDI_FOUND AND APPLE) if (RTMIDI_FOUND AND NOT DISABLE_RTMIDI)
find_library(CoreMIDI CoreMIDI)
add_definitions(-D__MACOSX_CORE__) add_definitions(-DHAVE_RTMIDI)
target_link_libraries(${TARGET_NAME} ${CoreMIDI}) include_directories(SYSTEM ${RTMIDI_INCLUDE_DIR})
target_link_libraries(${TARGET_NAME} "${RTMIDI_LIBRARY}")
if (APPLE)
find_library(CoreMIDI CoreMIDI)
add_definitions(-D__MACOSX_CORE__)
target_link_libraries(${TARGET_NAME} ${CoreMIDI})
endif()
endif() endif()
# include headers for interface and InterfaceConfig. # include headers for interface and InterfaceConfig.

View file

@ -7,7 +7,9 @@ Stephen Birarda, June 30, 2014
2. Copy RtMidi.h to externals/rtmidi/include. 2. Copy RtMidi.h to externals/rtmidi/include.
3. Copy RtMidi.cpp to externals/rtmidi/src 3. Compile the RtMidi library.
3. Copy either librtmidi.dylib (dynamic) or librtmidi.a (static) to externals/rtmidi/lib
4. Delete your build directory, run cmake and build, and you should be all set. 4. Delete your build directory, run cmake and build, and you should be all set.

View file

@ -67,7 +67,7 @@ Audio::Audio(int16_t initialJitterBufferSamples, QObject* parent) :
_proceduralAudioOutput(NULL), _proceduralAudioOutput(NULL),
_proceduralOutputDevice(NULL), _proceduralOutputDevice(NULL),
_inputRingBuffer(0), _inputRingBuffer(0),
_ringBuffer(NETWORK_BUFFER_LENGTH_SAMPLES_STEREO), _ringBuffer(NETWORK_BUFFER_LENGTH_SAMPLES_STEREO, false, 100),
_isStereoInput(false), _isStereoInput(false),
_averagedLatency(0.0), _averagedLatency(0.0),
_measuredJitter(0), _measuredJitter(0),
@ -869,14 +869,16 @@ void Audio::processReceivedAudio(const QByteArray& audioByteArray) {
_numFramesDisplayStarve = 10; _numFramesDisplayStarve = 10;
} }
// if there is anything in the ring buffer, decide what to do int numNetworkOutputSamples;
if (_ringBuffer.samplesAvailable() > 0) { if (Menu::getInstance()->isOptionChecked(MenuOption::DisableQAudioOutputOverflowCheck)) {
numNetworkOutputSamples = _ringBuffer.samplesAvailable();
int numNetworkOutputSamples = _ringBuffer.samplesAvailable(); } else {
int numDeviceOutputSamples = numNetworkOutputSamples / networkOutputToOutputRatio; int numSamplesAudioOutputRoomFor = _audioOutput->bytesFree() / sizeof(int16_t);
numNetworkOutputSamples = std::min(_ringBuffer.samplesAvailable(), (int)(numSamplesAudioOutputRoomFor * networkOutputToOutputRatio));
QByteArray outputBuffer; }
outputBuffer.resize(numDeviceOutputSamples * sizeof(int16_t));
// if there is data in the ring buffer and room in the audio output, decide what to do
if (numNetworkOutputSamples > 0) {
int numSamplesNeededToStartPlayback = std::min(NETWORK_BUFFER_LENGTH_SAMPLES_STEREO + (_jitterBufferSamples * 2), int numSamplesNeededToStartPlayback = std::min(NETWORK_BUFFER_LENGTH_SAMPLES_STEREO + (_jitterBufferSamples * 2),
_ringBuffer.getSampleCapacity()); _ringBuffer.getSampleCapacity());
@ -885,6 +887,11 @@ void Audio::processReceivedAudio(const QByteArray& audioByteArray) {
// We are still waiting for enough samples to begin playback // We are still waiting for enough samples to begin playback
// qDebug() << numNetworkOutputSamples << " samples so far, waiting for " << numSamplesNeededToStartPlayback; // qDebug() << numNetworkOutputSamples << " samples so far, waiting for " << numSamplesNeededToStartPlayback;
} else { } else {
int numDeviceOutputSamples = numNetworkOutputSamples / networkOutputToOutputRatio;
QByteArray outputBuffer;
outputBuffer.resize(numDeviceOutputSamples * sizeof(int16_t));
// We are either already playing back, or we have enough audio to start playing back. // We are either already playing back, or we have enough audio to start playing back.
//qDebug() << "pushing " << numNetworkOutputSamples; //qDebug() << "pushing " << numNetworkOutputSamples;
_ringBuffer.setIsStarved(false); _ringBuffer.setIsStarved(false);

35
interface/src/Hair.cpp Normal file
View file

@ -0,0 +1,35 @@
//
// Hair.cpp
// interface/src
//
// Created by Philip on June 26, 2014
// 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
//
// Creates single flexible vertlet-integrated strands that can be used for hair/fur/grass
#include "Hair.h"
#include "Util.h"
#include "world.h"
Hair::Hair() {
qDebug() << "Creating Hair";
}
void Hair::simulate(float deltaTime) {
}
void Hair::render() {
//
// Before calling this function, translate/rotate to the origin of the owning object
glPushMatrix();
glColor3f(1.0f, 1.0f, 0.0f);
glutSolidSphere(1.0f, 15, 15);
glPopMatrix();
}

35
interface/src/Hair.h Normal file
View file

@ -0,0 +1,35 @@
//
// Hair.h
// interface/src
//
// Created by Philip on June 26, 2014
// 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_Hair_h
#define hifi_Hair_h
#include <iostream>
#include <glm/glm.hpp>
#include <SharedUtil.h>
#include "GeometryUtil.h"
#include "InterfaceConfig.h"
#include "Util.h"
class Hair {
public:
Hair();
void simulate(float deltaTime);
void render();
private:
};
#endif // hifi_Hair_h

View file

@ -575,6 +575,8 @@ Menu::Menu() :
Qt::CTRL | Qt::SHIFT | Qt::Key_U, Qt::CTRL | Qt::SHIFT | Qt::Key_U,
false); false);
addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::DisableQAudioOutputOverflowCheck, 0, false);
addActionToQMenuAndActionHash(developerMenu, MenuOption::PasteToVoxel, addActionToQMenuAndActionHash(developerMenu, MenuOption::PasteToVoxel,
Qt::CTRL | Qt::SHIFT | Qt::Key_V, Qt::CTRL | Qt::SHIFT | Qt::Key_V,
this, this,

View file

@ -343,6 +343,7 @@ namespace MenuOption {
const QString DecreaseVoxelSize = "Decrease Voxel Size"; const QString DecreaseVoxelSize = "Decrease Voxel Size";
const QString DisableAutoAdjustLOD = "Disable Automatically Adjusting LOD"; const QString DisableAutoAdjustLOD = "Disable Automatically Adjusting LOD";
const QString DisableNackPackets = "Disable NACK Packets"; const QString DisableNackPackets = "Disable NACK Packets";
const QString DisableQAudioOutputOverflowCheck = "Disable QAudioOutput Overflow Check";
const QString DisplayFrustum = "Display Frustum"; const QString DisplayFrustum = "Display Frustum";
const QString DisplayHands = "Display Hands"; const QString DisplayHands = "Display Hands";
const QString DisplayHandTargets = "Display Hand Targets"; const QString DisplayHandTargets = "Display Hand Targets";

View file

@ -143,6 +143,11 @@ void Avatar::simulate(float deltaTime) {
if (Menu::getInstance()->isOptionChecked(MenuOption::StringHair)) { if (Menu::getInstance()->isOptionChecked(MenuOption::StringHair)) {
simulateHair(deltaTime); simulateHair(deltaTime);
} }
foreach (Hair* hair, _hairs) {
hair->simulate(deltaTime);
}
} }
// update position by velocity, and subtract the change added earlier for gravity // update position by velocity, and subtract the change added earlier for gravity
@ -380,6 +385,9 @@ void Avatar::renderBody(RenderMode renderMode, float glowLevel) {
getHead()->render(1.0f, modelRenderMode); getHead()->render(1.0f, modelRenderMode);
if (Menu::getInstance()->isOptionChecked(MenuOption::StringHair)) { if (Menu::getInstance()->isOptionChecked(MenuOption::StringHair)) {
renderHair(); renderHair();
foreach (Hair* hair, _hairs) {
hair->render();
}
} }
} }

View file

@ -19,6 +19,7 @@
#include <AvatarData.h> #include <AvatarData.h>
#include "Hair.h"
#include "Hand.h" #include "Hand.h"
#include "Head.h" #include "Head.h"
#include "InterfaceConfig.h" #include "InterfaceConfig.h"
@ -159,6 +160,7 @@ signals:
void collisionWithAvatar(const QUuid& myUUID, const QUuid& theirUUID, const CollisionInfo& collision); void collisionWithAvatar(const QUuid& myUUID, const QUuid& theirUUID, const CollisionInfo& collision);
protected: protected:
QVector<Hair*> _hairs;
SkeletonModel _skeletonModel; SkeletonModel _skeletonModel;
QVector<Model*> _attachmentModels; QVector<Model*> _attachmentModels;
float _bodyYawDelta; float _bodyYawDelta;

View file

@ -199,6 +199,9 @@ void MyAvatar::simulate(float deltaTime) {
PerformanceTimer perfTimer("MyAvatar::simulate/hair Simulate"); PerformanceTimer perfTimer("MyAvatar::simulate/hair Simulate");
if (Menu::getInstance()->isOptionChecked(MenuOption::StringHair)) { if (Menu::getInstance()->isOptionChecked(MenuOption::StringHair)) {
simulateHair(deltaTime); simulateHair(deltaTime);
foreach (Hair* hair, _hairs) {
hair->simulate(deltaTime);
}
} }
} }
@ -896,6 +899,9 @@ void MyAvatar::renderBody(RenderMode renderMode, float glowLevel) {
getHead()->render(1.0f, modelRenderMode); getHead()->render(1.0f, modelRenderMode);
if (Menu::getInstance()->isOptionChecked(MenuOption::StringHair)) { if (Menu::getInstance()->isOptionChecked(MenuOption::StringHair)) {
renderHair(); renderHair();
foreach (Hair* hair, _hairs) {
hair->render();
}
} }
} }
getHand()->render(true, modelRenderMode); getHand()->render(true, modelRenderMode);

View file

@ -13,14 +13,13 @@
#include "MIDIManager.h" #include "MIDIManager.h"
#ifdef HAVE_RTMIDI
MIDIManager& MIDIManager::getInstance() { MIDIManager& MIDIManager::getInstance() {
static MIDIManager sharedInstance; static MIDIManager sharedInstance;
return sharedInstance; return sharedInstance;
} }
void MIDIManager::midiCallback(double deltaTime, std::vector<unsigned char>* message, void* userData) { void MIDIManager::midiCallback(double deltaTime, std::vector<unsigned char>* message, void* userData) {
#ifdef HAVE_RTMIDI
MIDIEvent callbackEvent; MIDIEvent callbackEvent;
callbackEvent.deltaTime = deltaTime; callbackEvent.deltaTime = deltaTime;
@ -36,15 +35,19 @@ void MIDIManager::midiCallback(double deltaTime, std::vector<unsigned char>* mes
} }
emit getInstance().midiEvent(callbackEvent); emit getInstance().midiEvent(callbackEvent);
#endif
} }
MIDIManager::~MIDIManager() { MIDIManager::~MIDIManager() {
#ifdef HAVE_RTMIDI
delete _midiInput; delete _midiInput;
#endif
} }
const int DEFAULT_MIDI_PORT = 0; const int DEFAULT_MIDI_PORT = 0;
void MIDIManager::openDefaultPort() { void MIDIManager::openDefaultPort() {
#ifdef HAVE_RTMIDI
if (!_midiInput) { if (!_midiInput) {
_midiInput = new RtMidiIn(); _midiInput = new RtMidiIn();
@ -63,6 +66,5 @@ void MIDIManager::openDefaultPort() {
_midiInput = NULL; _midiInput = NULL;
} }
} }
} #endif
}
#endif

View file

@ -12,14 +12,14 @@
#ifndef hifi_MIDIManager_h #ifndef hifi_MIDIManager_h
#define hifi_MIDIManager_h #define hifi_MIDIManager_h
#ifdef HAVE_RTMIDI
#include <QtCore/QObject> #include <QtCore/QObject>
#include <QtScript/QScriptEngine> #include <QtScript/QScriptEngine>
#include <MIDIEvent.h> #include <MIDIEvent.h>
#ifdef HAVE_RTMIDI
#include <RtMidi.h> #include <RtMidi.h>
#endif
class MIDIManager : public QObject { class MIDIManager : public QObject {
Q_OBJECT Q_OBJECT
@ -36,7 +36,9 @@ public:
~MIDIManager(); ~MIDIManager();
void openDefaultPort(); void openDefaultPort();
#ifdef HAVE_RTMIDI
bool hasDevice() const { return !!_midiInput; } bool hasDevice() const { return !!_midiInput; }
#endif
public slots: public slots:
unsigned int NoteOn() const { return 144; } unsigned int NoteOn() const { return 144; }
unsigned int NoteOff() const { return 128; } unsigned int NoteOff() const { return 128; }
@ -46,10 +48,10 @@ signals:
void midiEvent(const MIDIEvent& event); void midiEvent(const MIDIEvent& event);
private: private:
#ifdef HAVE_RTMIDI
RtMidiIn* _midiInput; RtMidiIn* _midiInput;
};
#endif #endif
};
#endif // hifi_MIDIManager_h #endif // hifi_MIDIManager_h

View file

@ -22,7 +22,7 @@
Overlay::Overlay() : Overlay::Overlay() :
_parent(NULL), _parent(NULL),
_alpha(DEFAULT_ALPHA), _alpha(DEFAULT_ALPHA),
_color(DEFAULT_BACKGROUND_COLOR), _color(DEFAULT_OVERLAY_COLOR),
_visible(true), _visible(true),
_anchor(NO_ANCHOR) _anchor(NO_ANCHOR)
{ {

View file

@ -21,7 +21,7 @@
#include <SharedUtil.h> // for xColor #include <SharedUtil.h> // for xColor
const xColor DEFAULT_BACKGROUND_COLOR = { 255, 255, 255 }; const xColor DEFAULT_OVERLAY_COLOR = { 255, 255, 255 };
const float DEFAULT_ALPHA = 0.7f; const float DEFAULT_ALPHA = 0.7f;
class Overlay : public QObject { class Overlay : public QObject {

View file

@ -18,6 +18,7 @@
#include "ui/TextRenderer.h" #include "ui/TextRenderer.h"
TextOverlay::TextOverlay() : TextOverlay::TextOverlay() :
_backgroundColor(DEFAULT_BACKGROUND_COLOR),
_leftMargin(DEFAULT_MARGIN), _leftMargin(DEFAULT_MARGIN),
_topMargin(DEFAULT_MARGIN), _topMargin(DEFAULT_MARGIN),
_fontSize(DEFAULT_FONTSIZE) _fontSize(DEFAULT_FONTSIZE)
@ -33,7 +34,7 @@ void TextOverlay::render() {
} }
const float MAX_COLOR = 255; const float MAX_COLOR = 255;
glColor4f(0 / MAX_COLOR, 0 / MAX_COLOR, 0 / MAX_COLOR, _alpha); glColor4f(_backgroundColor.red / MAX_COLOR, _backgroundColor.green / MAX_COLOR, _backgroundColor.blue / MAX_COLOR, _alpha);
glBegin(GL_QUADS); glBegin(GL_QUADS);
glVertex2f(_bounds.left(), _bounds.top()); glVertex2f(_bounds.left(), _bounds.top());
@ -82,6 +83,18 @@ void TextOverlay::setProperties(const QScriptValue& properties) {
setText(text.toVariant().toString()); setText(text.toVariant().toString());
} }
QScriptValue backgroundColor = properties.property("backgroundColor");
if (backgroundColor.isValid()) {
QScriptValue red = backgroundColor.property("red");
QScriptValue green = backgroundColor.property("green");
QScriptValue blue = backgroundColor.property("blue");
if (red.isValid() && green.isValid() && blue.isValid()) {
_backgroundColor.red = red.toVariant().toInt();
_backgroundColor.green = green.toVariant().toInt();
_backgroundColor.blue = blue.toVariant().toInt();
}
}
if (properties.property("leftMargin").isValid()) { if (properties.property("leftMargin").isValid()) {
setLeftMargin(properties.property("leftMargin").toVariant().toInt()); setLeftMargin(properties.property("leftMargin").toVariant().toInt());
} }

View file

@ -27,6 +27,7 @@
#include "Overlay.h" #include "Overlay.h"
#include "Overlay2D.h" #include "Overlay2D.h"
const xColor DEFAULT_BACKGROUND_COLOR = { 0, 0, 0 };
const int DEFAULT_MARGIN = 10; const int DEFAULT_MARGIN = 10;
const int DEFAULT_FONTSIZE = 11; const int DEFAULT_FONTSIZE = 11;
@ -54,6 +55,7 @@ public:
private: private:
QString _text; QString _text;
xColor _backgroundColor;
int _leftMargin; int _leftMargin;
int _topMargin; int _topMargin;
int _fontSize; int _fontSize;

View file

@ -99,7 +99,8 @@ PositionalAudioRingBuffer::PositionalAudioRingBuffer(PositionalAudioRingBuffer::
_listenerUnattenuatedZone(NULL), _listenerUnattenuatedZone(NULL),
_desiredJitterBufferFrames(1), _desiredJitterBufferFrames(1),
_currentJitterBufferFrames(-1), _currentJitterBufferFrames(-1),
_dynamicJitterBuffers(dynamicJitterBuffers) _dynamicJitterBuffers(dynamicJitterBuffers),
_consecutiveNotMixedCount(0)
{ {
} }
@ -129,7 +130,7 @@ int PositionalAudioRingBuffer::parseData(const QByteArray& packet) {
numSilentSamples = getSamplesPerFrame(); numSilentSamples = getSamplesPerFrame();
if (numSilentSamples > 0) { if (numSilentSamples > 0) {
if (_currentJitterBufferFrames > _desiredJitterBufferFrames) { if (_dynamicJitterBuffers && _currentJitterBufferFrames > _desiredJitterBufferFrames) {
// our current jitter buffer size exceeds its desired value, so ignore some silent // our current jitter buffer size exceeds its desired value, so ignore some silent
// frames to get that size as close to desired as possible // frames to get that size as close to desired as possible
int samplesPerFrame = getSamplesPerFrame(); int samplesPerFrame = getSamplesPerFrame();
@ -206,11 +207,12 @@ bool PositionalAudioRingBuffer::shouldBeAddedToMix() {
if (!isNotStarvedOrHasMinimumSamples(samplesPerFrame + desiredJitterBufferSamples)) { if (!isNotStarvedOrHasMinimumSamples(samplesPerFrame + desiredJitterBufferSamples)) {
// if the buffer was starved, allow it to accrue at least the desired number of // if the buffer was starved, allow it to accrue at least the desired number of
// jitter buffer frames before we start taking frames from it for mixing // jitter buffer frames before we start taking frames from it for mixing
if (_shouldOutputStarveDebug) { if (_shouldOutputStarveDebug) {
_shouldOutputStarveDebug = false; _shouldOutputStarveDebug = false;
} }
_consecutiveNotMixedCount++;
return false; return false;
} else if (samplesAvailable() < samplesPerFrame) { } else if (samplesAvailable() < samplesPerFrame) {
// if the buffer doesn't have a full frame of samples to take for mixing, it is starved // if the buffer doesn't have a full frame of samples to take for mixing, it is starved
@ -222,6 +224,7 @@ bool PositionalAudioRingBuffer::shouldBeAddedToMix() {
// reset our _shouldOutputStarveDebug to true so the next is printed // reset our _shouldOutputStarveDebug to true so the next is printed
_shouldOutputStarveDebug = true; _shouldOutputStarveDebug = true;
_consecutiveNotMixedCount++;
return false; return false;
} }
@ -231,6 +234,7 @@ bool PositionalAudioRingBuffer::shouldBeAddedToMix() {
// minus one (since a frame will be read immediately after this) is the length of the jitter buffer // minus one (since a frame will be read immediately after this) is the length of the jitter buffer
_currentJitterBufferFrames = samplesAvailable() / samplesPerFrame - 1; _currentJitterBufferFrames = samplesAvailable() / samplesPerFrame - 1;
_isStarved = false; _isStarved = false;
_consecutiveNotMixedCount = 0;
} }
// since we've read data from ring buffer at least once - we've started // since we've read data from ring buffer at least once - we've started

View file

@ -83,6 +83,8 @@ public:
int getDesiredJitterBufferFrames() const { return _desiredJitterBufferFrames; } int getDesiredJitterBufferFrames() const { return _desiredJitterBufferFrames; }
int getCurrentJitterBufferFrames() const { return _currentJitterBufferFrames; } int getCurrentJitterBufferFrames() const { return _currentJitterBufferFrames; }
int getConsecutiveNotMixedCount() const { return _consecutiveNotMixedCount; }
protected: protected:
// disallow copying of PositionalAudioRingBuffer objects // disallow copying of PositionalAudioRingBuffer objects
PositionalAudioRingBuffer(const PositionalAudioRingBuffer&); PositionalAudioRingBuffer(const PositionalAudioRingBuffer&);
@ -107,9 +109,7 @@ protected:
bool _dynamicJitterBuffers; bool _dynamicJitterBuffers;
// extra stats // extra stats
int _starveCount; int _consecutiveNotMixedCount;
int _silentFramesDropped;
}; };
#endif // hifi_PositionalAudioRingBuffer_h #endif // hifi_PositionalAudioRingBuffer_h