mirror of
https://github.com/overte-org/overte.git
synced 2025-04-20 11:45:36 +02:00
Merge branch 'master' of https://github.com/highfidelity/hifi into metavoxels
This commit is contained in:
commit
2dbe72a818
24 changed files with 321 additions and 118 deletions
|
@ -32,14 +32,6 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
|||
# Instruct CMake to run moc automatically when needed.
|
||||
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
|
||||
if (NOT WIN32)
|
||||
add_subdirectory(animation-server)
|
||||
|
|
|
@ -138,11 +138,14 @@ void AudioMixerClientData::pushBuffersAfterFrameSend() {
|
|||
// this was a used buffer, push the output pointer forwards
|
||||
PositionalAudioRingBuffer* audioBuffer = *i;
|
||||
|
||||
const int INJECTOR_CONSECUTIVE_NOT_MIXED_THRESHOLD = 100;
|
||||
|
||||
if (audioBuffer->willBeAddedToMix()) {
|
||||
audioBuffer->shiftReadPosition(audioBuffer->getSamplesPerFrame());
|
||||
audioBuffer->setWillBeAddedToMix(false);
|
||||
} 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
|
||||
// also delete its sequence number stats
|
||||
QUuid streamIdentifier = ((InjectedAudioRingBuffer*)audioBuffer)->getStreamIdentifier();
|
||||
|
|
|
@ -26,8 +26,8 @@ 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})
|
||||
find_library(RTMIDI_LIBRARY NAMES rtmidi PATH_SUFFIXES lib HINTS ${RTMIDI_SEARCH_DIRS})
|
||||
|
||||
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 ()
|
153
examples/clap.js
153
examples/clap.js
|
@ -10,27 +10,34 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
function length(v) {
|
||||
return Math.sqrt(v.x * v.x + v.y * v.y + v.z * v.z);
|
||||
}
|
||||
var clapAnimation = "https://s3-us-west-1.amazonaws.com/highfidelity-public/animations/ClapAnimations/ClapHands_Standing.fbx";
|
||||
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) {
|
||||
print(v.x + ", " + v.y + ", " + v.z + "\n");
|
||||
}
|
||||
var claps = [];
|
||||
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 rval = { x: a.x - b.x, y: a.y - b.y, z: a.z - b.z };
|
||||
return rval;
|
||||
}
|
||||
var clappingNow = false;
|
||||
var collectedClicks = 0;
|
||||
|
||||
// First, load the clap sound from a URL
|
||||
var clap1 = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/claps/clap1.raw");
|
||||
var clap2 = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/claps/clap2.raw");
|
||||
var clap3 = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/claps/clap3.raw");
|
||||
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 clickClappingNow = false;
|
||||
var CLAP_START_RATE = 15.0;
|
||||
var clapRate = CLAP_START_RATE;
|
||||
var startedTimer = false;
|
||||
|
||||
var clapping = new Array();
|
||||
clapping[0] = false;
|
||||
|
@ -38,36 +45,94 @@ clapping[1] = false;
|
|||
|
||||
function maybePlaySound(deltaTime) {
|
||||
// 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 palmVelocity = Controller.getSpatialControlVelocity(palm * 2 + 1);
|
||||
var speed = length(palmVelocity);
|
||||
|
||||
const CLAP_SPEED = 0.2;
|
||||
const CLAP_DISTANCE = 0.2;
|
||||
var animationDetails = MyAvatar.getAnimationDetails(clapAnimation);
|
||||
|
||||
if (!clapping[palm] && (distanceBetween < CLAP_DISTANCE) && (speed > CLAP_SPEED)) {
|
||||
var options = new AudioInjectionOptions();
|
||||
options.position = palm1Position;
|
||||
options.volume = speed / 2.0;
|
||||
if (options.volume > 1.0) options.volume = 1.0;
|
||||
which = Math.floor((Math.random() * 6) + 1);
|
||||
if (which == 1) { Audio.playSound(clap1, options); }
|
||||
else if (which == 2) { Audio.playSound(clap2, options); }
|
||||
else if (which == 3) { Audio.playSound(clap3, options); }
|
||||
else if (which == 4) { Audio.playSound(clap4, options); }
|
||||
else if (which == 5) { Audio.playSound(clap5, options); }
|
||||
else { Audio.playSound(clap6, options); }
|
||||
Audio.playSound(clap, options);
|
||||
clapping[palm] = true;
|
||||
} else if (clapping[palm] && (speed < (CLAP_SPEED / 4.0))) {
|
||||
clapping[palm] = false;
|
||||
}
|
||||
var frame = Math.floor(animationDetails.frameIndex);
|
||||
|
||||
if (frame != lastAnimFrame) {
|
||||
print("frame " + frame);
|
||||
lastAnimFrame = frame;
|
||||
}
|
||||
for (var i = 0; i < startEndFrames.length; i++) {
|
||||
if (frame == startEndFrames[i].start && (frame != lastClapFrame)) {
|
||||
playClap(1.0, Camera.getPosition());
|
||||
lastClapFrame = frame;
|
||||
}
|
||||
}
|
||||
|
||||
var palm1Position = MyAvatar.getLeftPalmPosition();
|
||||
var palm2Position = MyAvatar.getRightPalmPosition();
|
||||
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
|
||||
Script.update.connect(maybePlaySound);
|
||||
Script.update.connect(maybePlaySound);
|
||||
//Controller.keyPressEvent.connect(keyPressEvent);
|
|
@ -57,7 +57,7 @@ var LocationMenu = function(opts) {
|
|||
y: 0,
|
||||
width: menuWidth + 10,
|
||||
height: (menuHeight * (pageSize + 1)) + 10,
|
||||
color: { red: 0, green: 0, blue: 0},
|
||||
backgroundColor: { red: 0, green: 0, blue: 0},
|
||||
topMargin: 4,
|
||||
leftMargin: 4,
|
||||
text: "",
|
||||
|
@ -71,7 +71,7 @@ var LocationMenu = function(opts) {
|
|||
y: 0,
|
||||
width: menuWidth,
|
||||
height: menuHeight,
|
||||
color: inactiveColor,
|
||||
backgroundColor: inactiveColor,
|
||||
topMargin: margin,
|
||||
leftMargin: margin,
|
||||
text: (i == 0) ? "Loading..." : "",
|
||||
|
@ -85,7 +85,7 @@ var LocationMenu = function(opts) {
|
|||
y: 0,
|
||||
width: menuWidth / 2,
|
||||
height: menuHeight,
|
||||
color: disabledColor,
|
||||
backgroundColor: disabledColor,
|
||||
topMargin: margin,
|
||||
leftMargin: margin,
|
||||
text: "Previous",
|
||||
|
@ -97,7 +97,7 @@ var LocationMenu = function(opts) {
|
|||
y: 0,
|
||||
width: menuWidth / 2,
|
||||
height: menuHeight,
|
||||
color: disabledColor,
|
||||
backgroundColor: disabledColor,
|
||||
topMargin: margin,
|
||||
leftMargin: margin,
|
||||
text: "Next",
|
||||
|
@ -175,10 +175,10 @@ var LocationMenu = function(opts) {
|
|||
if (start + i < this.locations.length) {
|
||||
location = this.locations[start + i];
|
||||
update.text = (start + i + 1) + ". " + location.username;
|
||||
update.color = inactiveColor;
|
||||
update.backgroundColor = inactiveColor;
|
||||
} else {
|
||||
update.text = "";
|
||||
update.color = disabledColor;
|
||||
update.backgroundColor = disabledColor;
|
||||
}
|
||||
Overlays.editOverlay(this.menuItems[i].overlay, update);
|
||||
this.menuItems[i].location = location;
|
||||
|
@ -187,8 +187,8 @@ var LocationMenu = function(opts) {
|
|||
this.previousEnabled = pageNumber > 0;
|
||||
this.nextEnabled = pageNumber < (this.numPages - 1);
|
||||
|
||||
Overlays.editOverlay(this.previousButton, { color: this.previousEnabled ? prevNextColor : disabledColor});
|
||||
Overlays.editOverlay(this.nextButton, { color: this.nextEnabled ? prevNextColor : disabledColor });
|
||||
Overlays.editOverlay(this.previousButton, { backgroundColor: this.previousEnabled ? prevNextColor : disabledColor});
|
||||
Overlays.editOverlay(this.nextButton, { backgroundColor: this.nextEnabled ? prevNextColor : disabledColor });
|
||||
}
|
||||
|
||||
this.mousePressEvent = function(event) {
|
||||
|
@ -198,17 +198,17 @@ var LocationMenu = function(opts) {
|
|||
self.toggleMenu();
|
||||
} else if (clickedOverlay == self.previousButton) {
|
||||
if (self.previousEnabled) {
|
||||
Overlays.editOverlay(clickedOverlay, { color: activeColor });
|
||||
Overlays.editOverlay(clickedOverlay, { backgroundColor: activeColor });
|
||||
}
|
||||
} else if (clickedOverlay == self.nextButton) {
|
||||
if (self.nextEnabled) {
|
||||
Overlays.editOverlay(clickedOverlay, { color: activeColor });
|
||||
Overlays.editOverlay(clickedOverlay, { backgroundColor: activeColor });
|
||||
}
|
||||
} else {
|
||||
for (var i = 0; i < self.menuItems.length; i++) {
|
||||
if (clickedOverlay == self.menuItems[i].overlay) {
|
||||
if (self.menuItems[i].location != null) {
|
||||
Overlays.editOverlay(clickedOverlay, { color: activeColor });
|
||||
Overlays.editOverlay(clickedOverlay, { backgroundColor: activeColor });
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -221,19 +221,19 @@ var LocationMenu = function(opts) {
|
|||
|
||||
if (clickedOverlay == self.previousButton) {
|
||||
if (self.previousEnabled) {
|
||||
Overlays.editOverlay(clickedOverlay, { color: inactiveColor });
|
||||
Overlays.editOverlay(clickedOverlay, { backgroundColor: inactiveColor });
|
||||
self.goToPage(self.page - 1);
|
||||
}
|
||||
} else if (clickedOverlay == self.nextButton) {
|
||||
if (self.nextEnabled) {
|
||||
Overlays.editOverlay(clickedOverlay, { color: inactiveColor });
|
||||
Overlays.editOverlay(clickedOverlay, { backgroundColor: inactiveColor });
|
||||
self.goToPage(self.page + 1);
|
||||
}
|
||||
} else {
|
||||
for (var i = 0; i < self.menuItems.length; i++) {
|
||||
if (clickedOverlay == self.menuItems[i].overlay) {
|
||||
if (self.menuItems[i].location != null) {
|
||||
Overlays.editOverlay(clickedOverlay, { color: inactiveColor });
|
||||
Overlays.editOverlay(clickedOverlay, { backgroundColor: inactiveColor });
|
||||
var location = self.menuItems[i].location;
|
||||
Window.location = "hifi://" + location.domain + "/"
|
||||
+ location.x + "," + location.y + "," + location.z;
|
||||
|
|
|
@ -18,13 +18,16 @@ var RIGHT = 1;
|
|||
var lastLeftFrame = 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 SMOOTH_FACTOR = 0.80;
|
||||
var leftDirection = true;
|
||||
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) {
|
||||
var leftTriggerValue = Math.sqrt(Controller.getTriggerValue(LEFT));
|
||||
var rightTriggerValue = Math.sqrt(Controller.getTriggerValue(RIGHT));
|
||||
var leftTriggerValue = Controller.getTriggerValue(LEFT);
|
||||
var rightTriggerValue = Controller.getTriggerValue(RIGHT);
|
||||
|
||||
var leftFrame, rightFrame;
|
||||
|
||||
|
@ -32,10 +35,31 @@ Script.update.connect(function(deltaTime) {
|
|||
leftFrame = (leftTriggerValue * LAST_FRAME) * (1.0 - SMOOTH_FACTOR) + lastLeftFrame * 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){
|
||||
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) {
|
||||
MyAvatar.stopAnimation(rightHandAnimation);
|
||||
|
|
|
@ -111,16 +111,6 @@ 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})
|
||||
|
||||
|
@ -151,6 +141,7 @@ find_package(Sixense)
|
|||
find_package(Visage)
|
||||
find_package(ZLIB)
|
||||
find_package(Qxmpp)
|
||||
find_package(RtMidi)
|
||||
|
||||
# include the Sixense library for Razer Hydra if available
|
||||
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}")
|
||||
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})
|
||||
# and with RtMidi for RtMidi control
|
||||
if (RTMIDI_FOUND AND NOT DISABLE_RTMIDI)
|
||||
|
||||
add_definitions(-DHAVE_RTMIDI)
|
||||
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()
|
||||
|
||||
# include headers for interface and InterfaceConfig.
|
||||
|
|
4
interface/external/rtmidi/readme.txt
vendored
4
interface/external/rtmidi/readme.txt
vendored
|
@ -7,7 +7,9 @@ Stephen Birarda, June 30, 2014
|
|||
|
||||
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.
|
||||
|
||||
|
|
|
@ -67,7 +67,7 @@ Audio::Audio(int16_t initialJitterBufferSamples, QObject* parent) :
|
|||
_proceduralAudioOutput(NULL),
|
||||
_proceduralOutputDevice(NULL),
|
||||
_inputRingBuffer(0),
|
||||
_ringBuffer(NETWORK_BUFFER_LENGTH_SAMPLES_STEREO),
|
||||
_ringBuffer(NETWORK_BUFFER_LENGTH_SAMPLES_STEREO, false, 100),
|
||||
_isStereoInput(false),
|
||||
_averagedLatency(0.0),
|
||||
_measuredJitter(0),
|
||||
|
@ -869,14 +869,16 @@ void Audio::processReceivedAudio(const QByteArray& audioByteArray) {
|
|||
_numFramesDisplayStarve = 10;
|
||||
}
|
||||
|
||||
// if there is anything in the ring buffer, decide what to do
|
||||
if (_ringBuffer.samplesAvailable() > 0) {
|
||||
|
||||
int numNetworkOutputSamples = _ringBuffer.samplesAvailable();
|
||||
int numDeviceOutputSamples = numNetworkOutputSamples / networkOutputToOutputRatio;
|
||||
|
||||
QByteArray outputBuffer;
|
||||
outputBuffer.resize(numDeviceOutputSamples * sizeof(int16_t));
|
||||
int numNetworkOutputSamples;
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::DisableQAudioOutputOverflowCheck)) {
|
||||
numNetworkOutputSamples = _ringBuffer.samplesAvailable();
|
||||
} else {
|
||||
int numSamplesAudioOutputRoomFor = _audioOutput->bytesFree() / sizeof(int16_t);
|
||||
numNetworkOutputSamples = std::min(_ringBuffer.samplesAvailable(), (int)(numSamplesAudioOutputRoomFor * networkOutputToOutputRatio));
|
||||
}
|
||||
|
||||
// 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),
|
||||
_ringBuffer.getSampleCapacity());
|
||||
|
@ -885,6 +887,11 @@ void Audio::processReceivedAudio(const QByteArray& audioByteArray) {
|
|||
// We are still waiting for enough samples to begin playback
|
||||
// qDebug() << numNetworkOutputSamples << " samples so far, waiting for " << numSamplesNeededToStartPlayback;
|
||||
} 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.
|
||||
//qDebug() << "pushing " << numNetworkOutputSamples;
|
||||
_ringBuffer.setIsStarved(false);
|
||||
|
|
35
interface/src/Hair.cpp
Normal file
35
interface/src/Hair.cpp
Normal 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
35
interface/src/Hair.h
Normal 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
|
|
@ -575,6 +575,8 @@ Menu::Menu() :
|
|||
Qt::CTRL | Qt::SHIFT | Qt::Key_U,
|
||||
false);
|
||||
|
||||
addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::DisableQAudioOutputOverflowCheck, 0, false);
|
||||
|
||||
addActionToQMenuAndActionHash(developerMenu, MenuOption::PasteToVoxel,
|
||||
Qt::CTRL | Qt::SHIFT | Qt::Key_V,
|
||||
this,
|
||||
|
|
|
@ -343,6 +343,7 @@ namespace MenuOption {
|
|||
const QString DecreaseVoxelSize = "Decrease Voxel Size";
|
||||
const QString DisableAutoAdjustLOD = "Disable Automatically Adjusting LOD";
|
||||
const QString DisableNackPackets = "Disable NACK Packets";
|
||||
const QString DisableQAudioOutputOverflowCheck = "Disable QAudioOutput Overflow Check";
|
||||
const QString DisplayFrustum = "Display Frustum";
|
||||
const QString DisplayHands = "Display Hands";
|
||||
const QString DisplayHandTargets = "Display Hand Targets";
|
||||
|
|
|
@ -143,6 +143,11 @@ void Avatar::simulate(float deltaTime) {
|
|||
if (Menu::getInstance()->isOptionChecked(MenuOption::StringHair)) {
|
||||
simulateHair(deltaTime);
|
||||
}
|
||||
|
||||
foreach (Hair* hair, _hairs) {
|
||||
hair->simulate(deltaTime);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 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);
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::StringHair)) {
|
||||
renderHair();
|
||||
foreach (Hair* hair, _hairs) {
|
||||
hair->render();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
#include <AvatarData.h>
|
||||
|
||||
#include "Hair.h"
|
||||
#include "Hand.h"
|
||||
#include "Head.h"
|
||||
#include "InterfaceConfig.h"
|
||||
|
@ -159,6 +160,7 @@ signals:
|
|||
void collisionWithAvatar(const QUuid& myUUID, const QUuid& theirUUID, const CollisionInfo& collision);
|
||||
|
||||
protected:
|
||||
QVector<Hair*> _hairs;
|
||||
SkeletonModel _skeletonModel;
|
||||
QVector<Model*> _attachmentModels;
|
||||
float _bodyYawDelta;
|
||||
|
|
|
@ -199,6 +199,9 @@ void MyAvatar::simulate(float deltaTime) {
|
|||
PerformanceTimer perfTimer("MyAvatar::simulate/hair Simulate");
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::StringHair)) {
|
||||
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);
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::StringHair)) {
|
||||
renderHair();
|
||||
foreach (Hair* hair, _hairs) {
|
||||
hair->render();
|
||||
}
|
||||
}
|
||||
}
|
||||
getHand()->render(true, modelRenderMode);
|
||||
|
|
|
@ -13,14 +13,13 @@
|
|||
|
||||
#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) {
|
||||
#ifdef HAVE_RTMIDI
|
||||
|
||||
MIDIEvent callbackEvent;
|
||||
callbackEvent.deltaTime = deltaTime;
|
||||
|
@ -36,15 +35,19 @@ void MIDIManager::midiCallback(double deltaTime, std::vector<unsigned char>* mes
|
|||
}
|
||||
|
||||
emit getInstance().midiEvent(callbackEvent);
|
||||
#endif
|
||||
}
|
||||
|
||||
MIDIManager::~MIDIManager() {
|
||||
#ifdef HAVE_RTMIDI
|
||||
delete _midiInput;
|
||||
#endif
|
||||
}
|
||||
|
||||
const int DEFAULT_MIDI_PORT = 0;
|
||||
|
||||
void MIDIManager::openDefaultPort() {
|
||||
#ifdef HAVE_RTMIDI
|
||||
if (!_midiInput) {
|
||||
_midiInput = new RtMidiIn();
|
||||
|
||||
|
@ -63,6 +66,5 @@ void MIDIManager::openDefaultPort() {
|
|||
_midiInput = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
}
|
|
@ -12,14 +12,14 @@
|
|||
#ifndef hifi_MIDIManager_h
|
||||
#define hifi_MIDIManager_h
|
||||
|
||||
#ifdef HAVE_RTMIDI
|
||||
|
||||
#include <QtCore/QObject>
|
||||
#include <QtScript/QScriptEngine>
|
||||
|
||||
#include <MIDIEvent.h>
|
||||
|
||||
#ifdef HAVE_RTMIDI
|
||||
#include <RtMidi.h>
|
||||
#endif
|
||||
|
||||
class MIDIManager : public QObject {
|
||||
Q_OBJECT
|
||||
|
@ -36,7 +36,9 @@ public:
|
|||
~MIDIManager();
|
||||
|
||||
void openDefaultPort();
|
||||
#ifdef HAVE_RTMIDI
|
||||
bool hasDevice() const { return !!_midiInput; }
|
||||
#endif
|
||||
public slots:
|
||||
unsigned int NoteOn() const { return 144; }
|
||||
unsigned int NoteOff() const { return 128; }
|
||||
|
@ -46,10 +48,10 @@ signals:
|
|||
void midiEvent(const MIDIEvent& event);
|
||||
|
||||
private:
|
||||
#ifdef HAVE_RTMIDI
|
||||
RtMidiIn* _midiInput;
|
||||
};
|
||||
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
#endif // hifi_MIDIManager_h
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
Overlay::Overlay() :
|
||||
_parent(NULL),
|
||||
_alpha(DEFAULT_ALPHA),
|
||||
_color(DEFAULT_BACKGROUND_COLOR),
|
||||
_color(DEFAULT_OVERLAY_COLOR),
|
||||
_visible(true),
|
||||
_anchor(NO_ANCHOR)
|
||||
{
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
|
||||
#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;
|
||||
|
||||
class Overlay : public QObject {
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include "ui/TextRenderer.h"
|
||||
|
||||
TextOverlay::TextOverlay() :
|
||||
_backgroundColor(DEFAULT_BACKGROUND_COLOR),
|
||||
_leftMargin(DEFAULT_MARGIN),
|
||||
_topMargin(DEFAULT_MARGIN),
|
||||
_fontSize(DEFAULT_FONTSIZE)
|
||||
|
@ -33,7 +34,7 @@ void TextOverlay::render() {
|
|||
}
|
||||
|
||||
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);
|
||||
glVertex2f(_bounds.left(), _bounds.top());
|
||||
|
@ -82,6 +83,18 @@ void TextOverlay::setProperties(const QScriptValue& properties) {
|
|||
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()) {
|
||||
setLeftMargin(properties.property("leftMargin").toVariant().toInt());
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include "Overlay.h"
|
||||
#include "Overlay2D.h"
|
||||
|
||||
const xColor DEFAULT_BACKGROUND_COLOR = { 0, 0, 0 };
|
||||
const int DEFAULT_MARGIN = 10;
|
||||
const int DEFAULT_FONTSIZE = 11;
|
||||
|
||||
|
@ -54,6 +55,7 @@ public:
|
|||
private:
|
||||
|
||||
QString _text;
|
||||
xColor _backgroundColor;
|
||||
int _leftMargin;
|
||||
int _topMargin;
|
||||
int _fontSize;
|
||||
|
|
|
@ -99,7 +99,8 @@ PositionalAudioRingBuffer::PositionalAudioRingBuffer(PositionalAudioRingBuffer::
|
|||
_listenerUnattenuatedZone(NULL),
|
||||
_desiredJitterBufferFrames(1),
|
||||
_currentJitterBufferFrames(-1),
|
||||
_dynamicJitterBuffers(dynamicJitterBuffers)
|
||||
_dynamicJitterBuffers(dynamicJitterBuffers),
|
||||
_consecutiveNotMixedCount(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -129,7 +130,7 @@ int PositionalAudioRingBuffer::parseData(const QByteArray& packet) {
|
|||
numSilentSamples = getSamplesPerFrame();
|
||||
|
||||
if (numSilentSamples > 0) {
|
||||
if (_currentJitterBufferFrames > _desiredJitterBufferFrames) {
|
||||
if (_dynamicJitterBuffers && _currentJitterBufferFrames > _desiredJitterBufferFrames) {
|
||||
// our current jitter buffer size exceeds its desired value, so ignore some silent
|
||||
// frames to get that size as close to desired as possible
|
||||
int samplesPerFrame = getSamplesPerFrame();
|
||||
|
@ -206,11 +207,12 @@ bool PositionalAudioRingBuffer::shouldBeAddedToMix() {
|
|||
if (!isNotStarvedOrHasMinimumSamples(samplesPerFrame + desiredJitterBufferSamples)) {
|
||||
// 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
|
||||
|
||||
|
||||
if (_shouldOutputStarveDebug) {
|
||||
_shouldOutputStarveDebug = false;
|
||||
}
|
||||
|
||||
_consecutiveNotMixedCount++;
|
||||
return false;
|
||||
} else if (samplesAvailable() < samplesPerFrame) {
|
||||
// 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
|
||||
_shouldOutputStarveDebug = true;
|
||||
|
||||
_consecutiveNotMixedCount++;
|
||||
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
|
||||
_currentJitterBufferFrames = samplesAvailable() / samplesPerFrame - 1;
|
||||
_isStarved = false;
|
||||
_consecutiveNotMixedCount = 0;
|
||||
}
|
||||
|
||||
// since we've read data from ring buffer at least once - we've started
|
||||
|
|
|
@ -83,6 +83,8 @@ public:
|
|||
int getDesiredJitterBufferFrames() const { return _desiredJitterBufferFrames; }
|
||||
int getCurrentJitterBufferFrames() const { return _currentJitterBufferFrames; }
|
||||
|
||||
int getConsecutiveNotMixedCount() const { return _consecutiveNotMixedCount; }
|
||||
|
||||
protected:
|
||||
// disallow copying of PositionalAudioRingBuffer objects
|
||||
PositionalAudioRingBuffer(const PositionalAudioRingBuffer&);
|
||||
|
@ -107,9 +109,7 @@ protected:
|
|||
bool _dynamicJitterBuffers;
|
||||
|
||||
// extra stats
|
||||
int _starveCount;
|
||||
int _silentFramesDropped;
|
||||
|
||||
int _consecutiveNotMixedCount;
|
||||
};
|
||||
|
||||
#endif // hifi_PositionalAudioRingBuffer_h
|
||||
|
|
Loading…
Reference in a new issue