mirror of
https://github.com/overte-org/overte.git
synced 2025-08-10 04:53:25 +02:00
Merge pull request #6161 from jherico/controllers
Fix hand poses, air guitar chord and instrument changing and RAW sound file playback.
This commit is contained in:
commit
816cf3d516
3 changed files with 71 additions and 52 deletions
|
@ -90,7 +90,7 @@ var audioInjector = null;
|
||||||
var selectorPressed = false;
|
var selectorPressed = false;
|
||||||
var position;
|
var position;
|
||||||
|
|
||||||
MyAvatar.attach(guitarModel, "Hips", {x: -0.2, y: 0.0, z: 0.1}, Quat.fromPitchYawRollDegrees(90, 00, 90), 1.0);
|
MyAvatar.attach(guitarModel, "Hips", {x: leftHanded ? -0.2 : 0.2, y: 0.0, z: 0.1}, Quat.fromPitchYawRollDegrees(90, 00, leftHanded ? 75 : -75), 1.0);
|
||||||
|
|
||||||
function checkHands(deltaTime) {
|
function checkHands(deltaTime) {
|
||||||
var strumVelocity = Controller.getPoseValue(strumHand).velocity;
|
var strumVelocity = Controller.getPoseValue(strumHand).velocity;
|
||||||
|
@ -114,27 +114,32 @@ function checkHands(deltaTime) {
|
||||||
|
|
||||||
// Change guitars if button FWD (5) pressed
|
// Change guitars if button FWD (5) pressed
|
||||||
if (Controller.getValue(changeGuitar)) {
|
if (Controller.getValue(changeGuitar)) {
|
||||||
print("changeGuitar:" + changeGuitar);
|
|
||||||
if (!selectorPressed) {
|
if (!selectorPressed) {
|
||||||
|
print("changeGuitar:" + changeGuitar);
|
||||||
guitarSelector += NUM_CHORDS;
|
guitarSelector += NUM_CHORDS;
|
||||||
if (guitarSelector >= NUM_CHORDS * NUM_GUITARS) {
|
if (guitarSelector >= NUM_CHORDS * NUM_GUITARS) {
|
||||||
guitarSelector = 0;
|
guitarSelector = 0;
|
||||||
}
|
}
|
||||||
|
print("new guitarBase: " + guitarSelector);
|
||||||
|
stopAudio(true);
|
||||||
selectorPressed = true;
|
selectorPressed = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
selectorPressed = false;
|
selectorPressed = false;
|
||||||
}
|
}
|
||||||
//print("selectorPressed:" + selectorPressed);
|
|
||||||
|
|
||||||
if (Controller.getValue(chord1)) {
|
if (Controller.getValue(chord1)) {
|
||||||
whichChord = 1;
|
whichChord = 1;
|
||||||
|
stopAudio(true);
|
||||||
} else if (Controller.getValue(chord2)) {
|
} else if (Controller.getValue(chord2)) {
|
||||||
whichChord = 2;
|
whichChord = 2;
|
||||||
|
stopAudio(true);
|
||||||
} else if (Controller.getValue(chord3)) {
|
} else if (Controller.getValue(chord3)) {
|
||||||
whichChord = 3;
|
whichChord = 3;
|
||||||
|
stopAudio(true);
|
||||||
} else if (Controller.getValue(chord4)) {
|
} else if (Controller.getValue(chord4)) {
|
||||||
whichChord = 4;
|
whichChord = 4;
|
||||||
|
stopAudio(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
var STRUM_HEIGHT_ABOVE_PELVIS = 0.10;
|
var STRUM_HEIGHT_ABOVE_PELVIS = 0.10;
|
||||||
|
@ -154,26 +159,27 @@ function checkHands(deltaTime) {
|
||||||
lastPosition = strumHandPosition;
|
lastPosition = strumHandPosition;
|
||||||
}
|
}
|
||||||
|
|
||||||
function playChord(position, volume) {
|
function stopAudio(killInjector) {
|
||||||
if (audioInjector && audioInjector.isPlaying) {
|
if (audioInjector && audioInjector.isPlaying) {
|
||||||
print("stopped sound");
|
print("stopped sound");
|
||||||
audioInjector.stop();
|
audioInjector.stop();
|
||||||
}
|
}
|
||||||
|
if (killInjector) {
|
||||||
|
audioInjector = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function playChord(position, volume) {
|
||||||
|
stopAudio();
|
||||||
print("Played sound: " + whichChord + " at volume " + volume);
|
print("Played sound: " + whichChord + " at volume " + volume);
|
||||||
if (!audioInjector) {
|
if (!audioInjector) {
|
||||||
|
var index = guitarSelector + whichChord;
|
||||||
// FIXME - we apparenlty broke RAW file playback, so we need WAV files for all these chords. In the mean
|
var chord = chords[guitarSelector + whichChord];
|
||||||
// time, we will just play the heyMan wave file for all chords
|
|
||||||
var chord = heyManWave; // chords[guitarSelector + whichChord];
|
|
||||||
|
|
||||||
audioInjector = Audio.playSound(chord, { position: position, volume: volume });
|
audioInjector = Audio.playSound(chord, { position: position, volume: volume });
|
||||||
print("audioInjector: " + JSON.stringify(audioInjector));
|
|
||||||
} else {
|
} else {
|
||||||
print("audioInjector: " + JSON.stringify(audioInjector));
|
|
||||||
audioInjector.restart();
|
audioInjector.restart();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function keyPressEvent(event) {
|
function keyPressEvent(event) {
|
||||||
|
@ -181,15 +187,19 @@ function keyPressEvent(event) {
|
||||||
keyVolume = 0.4;
|
keyVolume = 0.4;
|
||||||
if (event.text == "1") {
|
if (event.text == "1") {
|
||||||
whichChord = 1;
|
whichChord = 1;
|
||||||
|
stopAudio(true);
|
||||||
playChord(MyAvatar.position, keyVolume);
|
playChord(MyAvatar.position, keyVolume);
|
||||||
} else if (event.text == "2") {
|
} else if (event.text == "2") {
|
||||||
whichChord = 2;
|
whichChord = 2;
|
||||||
|
stopAudio(true);
|
||||||
playChord(MyAvatar.position, keyVolume);
|
playChord(MyAvatar.position, keyVolume);
|
||||||
} else if (event.text == "3") {
|
} else if (event.text == "3") {
|
||||||
whichChord = 3;
|
whichChord = 3;
|
||||||
|
stopAudio(true);
|
||||||
playChord(MyAvatar.position, keyVolume);
|
playChord(MyAvatar.position, keyVolume);
|
||||||
} else if (event.text == "4") {
|
} else if (event.text == "4") {
|
||||||
whichChord = 4;
|
whichChord = 4;
|
||||||
|
stopAudio(true);
|
||||||
playChord(MyAvatar.position, keyVolume);
|
playChord(MyAvatar.position, keyVolume);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -197,6 +207,7 @@ function keyPressEvent(event) {
|
||||||
function scriptEnding() {
|
function scriptEnding() {
|
||||||
MyAvatar.detachOne(guitarModel);
|
MyAvatar.detachOne(guitarModel);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Connect a call back that happens every frame
|
// Connect a call back that happens every frame
|
||||||
Script.update.connect(checkHands);
|
Script.update.connect(checkHands);
|
||||||
Script.scriptEnding.connect(scriptEnding);
|
Script.scriptEnding.connect(scriptEnding);
|
||||||
|
|
|
@ -59,26 +59,18 @@ Sound::Sound(const QUrl& url, bool isStereo) :
|
||||||
void Sound::downloadFinished(const QByteArray& data) {
|
void Sound::downloadFinished(const QByteArray& data) {
|
||||||
// replace our byte array with the downloaded data
|
// replace our byte array with the downloaded data
|
||||||
QByteArray rawAudioByteArray = QByteArray(data);
|
QByteArray rawAudioByteArray = QByteArray(data);
|
||||||
QString fileName = getURL().fileName();
|
QString fileName = getURL().fileName().toLower();
|
||||||
|
|
||||||
const QString WAV_EXTENSION = ".wav";
|
|
||||||
|
|
||||||
|
static const QString WAV_EXTENSION = ".wav";
|
||||||
|
static const QString RAW_EXTENSION = ".raw";
|
||||||
if (fileName.endsWith(WAV_EXTENSION)) {
|
if (fileName.endsWith(WAV_EXTENSION)) {
|
||||||
|
|
||||||
QString headerContentType = "audio/x-wav";
|
|
||||||
//QByteArray headerContentType = reply->rawHeader("Content-Type");
|
|
||||||
|
|
||||||
// WAV audio file encountered
|
|
||||||
if (headerContentType == "audio/x-wav"
|
|
||||||
|| headerContentType == "audio/wav"
|
|
||||||
|| headerContentType == "audio/wave"
|
|
||||||
|| fileName.endsWith(WAV_EXTENSION)) {
|
|
||||||
|
|
||||||
QByteArray outputAudioByteArray;
|
QByteArray outputAudioByteArray;
|
||||||
|
|
||||||
interpretAsWav(rawAudioByteArray, outputAudioByteArray);
|
interpretAsWav(rawAudioByteArray, outputAudioByteArray);
|
||||||
downSample(outputAudioByteArray);
|
downSample(outputAudioByteArray);
|
||||||
} else {
|
trimFrames();
|
||||||
|
} else if (fileName.endsWith(RAW_EXTENSION)) {
|
||||||
// check if this was a stereo raw file
|
// check if this was a stereo raw file
|
||||||
// since it's raw the only way for us to know that is if the file was called .stereo.raw
|
// since it's raw the only way for us to know that is if the file was called .stereo.raw
|
||||||
if (fileName.toLower().endsWith("stereo.raw")) {
|
if (fileName.toLower().endsWith("stereo.raw")) {
|
||||||
|
@ -88,10 +80,9 @@ void Sound::downloadFinished(const QByteArray& data) {
|
||||||
|
|
||||||
// Process as RAW file
|
// Process as RAW file
|
||||||
downSample(rawAudioByteArray);
|
downSample(rawAudioByteArray);
|
||||||
}
|
|
||||||
trimFrames();
|
trimFrames();
|
||||||
} else {
|
} else {
|
||||||
qCDebug(audio) << "Network reply without 'Content-Type'.";
|
qCDebug(audio) << "Unknown sound file type";
|
||||||
}
|
}
|
||||||
|
|
||||||
_isReady = true;
|
_isReady = true;
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include <QtCore/QJsonArray>
|
#include <QtCore/QJsonArray>
|
||||||
|
|
||||||
#include <PathUtils.h>
|
#include <PathUtils.h>
|
||||||
|
#include <NumericalConstants.h>
|
||||||
|
|
||||||
#include "StandardController.h"
|
#include "StandardController.h"
|
||||||
#include "Logging.h"
|
#include "Logging.h"
|
||||||
|
@ -653,7 +654,16 @@ Input UserInputMapper::makeStandardInput(controller::StandardPoseChannel pose) {
|
||||||
return Input(STANDARD_DEVICE, pose, ChannelType::POSE);
|
return Input(STANDARD_DEVICE, pose, ChannelType::POSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static auto lastDebugTime = usecTimestampNow();
|
||||||
|
static auto debugRoutes = false;
|
||||||
|
static const auto DEBUG_INTERVAL = USECS_PER_SECOND;
|
||||||
|
|
||||||
void UserInputMapper::runMappings() {
|
void UserInputMapper::runMappings() {
|
||||||
|
auto now = usecTimestampNow();
|
||||||
|
if (now - lastDebugTime > DEBUG_INTERVAL) {
|
||||||
|
lastDebugTime = now;
|
||||||
|
debugRoutes = true;
|
||||||
|
}
|
||||||
static auto deviceNames = getDeviceNames();
|
static auto deviceNames = getDeviceNames();
|
||||||
for (auto endpointEntry : this->_endpointsByInput) {
|
for (auto endpointEntry : this->_endpointsByInput) {
|
||||||
endpointEntry.second->reset();
|
endpointEntry.second->reset();
|
||||||
|
@ -673,17 +683,17 @@ void UserInputMapper::runMappings() {
|
||||||
}
|
}
|
||||||
applyRoute(route);
|
applyRoute(route);
|
||||||
}
|
}
|
||||||
|
debugRoutes = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void UserInputMapper::applyRoute(const Route::Pointer& route) {
|
void UserInputMapper::applyRoute(const Route::Pointer& route) {
|
||||||
if (route->debug) {
|
if (debugRoutes && route->debug) {
|
||||||
qCDebug(controllers) << "Applying route " << route->json;
|
qCDebug(controllers) << "Applying route " << route->json;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (route->conditional) {
|
if (route->conditional) {
|
||||||
if (!route->conditional->satisfied()) {
|
if (!route->conditional->satisfied()) {
|
||||||
if (route->debug) {
|
if (debugRoutes && route->debug) {
|
||||||
qCDebug(controllers) << "Conditional failed";
|
qCDebug(controllers) << "Conditional failed";
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
@ -698,7 +708,7 @@ void UserInputMapper::applyRoute(const Route::Pointer& route) {
|
||||||
// I press the button. The exception is if I'm wiring a control back to itself
|
// I press the button. The exception is if I'm wiring a control back to itself
|
||||||
// in order to adjust my interface, like inverting the Y axis on an analog stick
|
// in order to adjust my interface, like inverting the Y axis on an analog stick
|
||||||
if (!source->readable()) {
|
if (!source->readable()) {
|
||||||
if (route->debug) {
|
if (debugRoutes && route->debug) {
|
||||||
qCDebug(controllers) << "Source unreadable";
|
qCDebug(controllers) << "Source unreadable";
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
@ -708,14 +718,14 @@ void UserInputMapper::applyRoute(const Route::Pointer& route) {
|
||||||
// THis could happen if the route destination failed to create
|
// THis could happen if the route destination failed to create
|
||||||
// FIXME: Maybe do not create the route if the destination failed and avoid this case ?
|
// FIXME: Maybe do not create the route if the destination failed and avoid this case ?
|
||||||
if (!destination) {
|
if (!destination) {
|
||||||
if (route->debug) {
|
if (debugRoutes && route->debug) {
|
||||||
qCDebug(controllers) << "Bad Destination";
|
qCDebug(controllers) << "Bad Destination";
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!destination->writeable()) {
|
if (!destination->writeable()) {
|
||||||
if (route->debug) {
|
if (debugRoutes && route->debug) {
|
||||||
qCDebug(controllers) << "Destination unwritable";
|
qCDebug(controllers) << "Destination unwritable";
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
@ -723,17 +733,24 @@ void UserInputMapper::applyRoute(const Route::Pointer& route) {
|
||||||
|
|
||||||
// Fetch the value, may have been overriden by previous loopback routes
|
// Fetch the value, may have been overriden by previous loopback routes
|
||||||
if (source->isPose()) {
|
if (source->isPose()) {
|
||||||
if (route->debug) {
|
|
||||||
qCDebug(controllers) << "Applying pose";
|
|
||||||
}
|
|
||||||
Pose value = getPose(source);
|
Pose value = getPose(source);
|
||||||
|
static const Pose IDENTITY_POSE { vec3(), quat() };
|
||||||
|
if (debugRoutes && route->debug) {
|
||||||
|
if (!value.valid) {
|
||||||
|
qCDebug(controllers) << "Applying invalid pose";
|
||||||
|
} else if (value == IDENTITY_POSE) {
|
||||||
|
qCDebug(controllers) << "Applying identity pose";
|
||||||
|
} else {
|
||||||
|
qCDebug(controllers) << "Applying valid pose";
|
||||||
|
}
|
||||||
|
}
|
||||||
// no filters yet for pose
|
// no filters yet for pose
|
||||||
destination->apply(value, Pose(), source);
|
destination->apply(value, Pose(), source);
|
||||||
} else {
|
} else {
|
||||||
// Fetch the value, may have been overriden by previous loopback routes
|
// Fetch the value, may have been overriden by previous loopback routes
|
||||||
float value = getValue(source);
|
float value = getValue(source);
|
||||||
|
|
||||||
if (route->debug) {
|
if (debugRoutes && route->debug) {
|
||||||
qCDebug(controllers) << "Value was " << value;
|
qCDebug(controllers) << "Value was " << value;
|
||||||
}
|
}
|
||||||
// Apply each of the filters.
|
// Apply each of the filters.
|
||||||
|
@ -741,7 +758,7 @@ void UserInputMapper::applyRoute(const Route::Pointer& route) {
|
||||||
value = filter->apply(value);
|
value = filter->apply(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (route->debug) {
|
if (debugRoutes && route->debug) {
|
||||||
qCDebug(controllers) << "Filtered value was " << value;
|
qCDebug(controllers) << "Filtered value was " << value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1148,13 +1165,13 @@ void UserInputMapper::enableMapping(const Mapping::Pointer& mapping) {
|
||||||
// because standard -> action is the first set of routes added.
|
// because standard -> action is the first set of routes added.
|
||||||
Route::List standardRoutes = mapping->routes;
|
Route::List standardRoutes = mapping->routes;
|
||||||
standardRoutes.remove_if([](const Route::Pointer& value) {
|
standardRoutes.remove_if([](const Route::Pointer& value) {
|
||||||
return (value->source->getInput().device == STANDARD_DEVICE);
|
return (value->source->getInput().device != STANDARD_DEVICE);
|
||||||
});
|
});
|
||||||
_standardRoutes.insert(_standardRoutes.begin(), standardRoutes.begin(), standardRoutes.end());
|
_standardRoutes.insert(_standardRoutes.begin(), standardRoutes.begin(), standardRoutes.end());
|
||||||
|
|
||||||
Route::List deviceRoutes = mapping->routes;
|
Route::List deviceRoutes = mapping->routes;
|
||||||
deviceRoutes.remove_if([](const Route::Pointer& value) {
|
deviceRoutes.remove_if([](const Route::Pointer& value) {
|
||||||
return (value->source->getInput().device != STANDARD_DEVICE);
|
return (value->source->getInput().device == STANDARD_DEVICE);
|
||||||
});
|
});
|
||||||
_deviceRoutes.insert(_deviceRoutes.begin(), deviceRoutes.begin(), deviceRoutes.end());
|
_deviceRoutes.insert(_deviceRoutes.begin(), deviceRoutes.begin(), deviceRoutes.end());
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue