Julian GroßFix building hifiOSC.4f441d25 months agoHistory
636 lines · 20.3 KB · C++
RawDownload
////  OscPlugin.cpp////  Created by Anthony Thibault on 2019/8/24//  Copyright 2019 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 "OscPlugin.h" #include <controllers/UserInputMapper.h>#include <QLoggingCategory>#include <PathUtils.h>#include <DebugDraw.h>#include <cassert>#include <NumericalConstants.h>#include <StreamUtils.h>#include <Preferences.h>#include <SettingHandle.h> Q_DECLARE_LOGGING_CATEGORY(inputplugins)Q_LOGGING_CATEGORY(inputplugins, "hifi.inputplugins") const char* OscPlugin::NAME = "Open Sound Control (OSC)";const char* OscPlugin::OSC_ID_STRING = "Open Sound Control (OSC)";const bool DEFAULT_ENABLED = false; enum class FaceCap {    BrowsU_C = 0,    BrowsD_L,    BrowsD_R,    BrowsU_L,    BrowsU_R,    EyeUp_L,    EyeUp_R,    EyeDown_L,    EyeDown_R,    EyeIn_L,    EyeIn_R,    EyeOut_L,    EyeOut_R,    EyeBlink_L,    EyeBlink_R,    EyeSquint_L,    EyeSquint_R,    EyeOpen_L,    EyeOpen_R,    Puff,    CheekSquint_L,    CheekSquint_R,    NoseSneer_L,    NoseSneer_R,    JawOpen,    JawFwd,    JawLeft,    JawRight,    LipsFunnel,    LipsPucker,    MouthLeft,    MouthRight,    LipsUpperClose,    LipsLowerClose,    MouthShrugUpper,    MouthShrugLower,    MouthClose,    MouthSmile_L,    MouthSmile_R,    MouthFrown_L,    MouthFrown_R,    MouthDimple_L,    MouthDimple_R,    MouthUpperUp_L,    MouthUpperUp_R,    MouthLowerDown_L,    MouthLowerDown_R,    MouthPress_L,    MouthPress_R,    LipsStretch_L,    LipsStretch_R,    TongueOut,    BlendshapeCount}; // used to mirror left/right shapes from FaceCap.// i.e. right and left shapes are swapped.FaceCap faceMirrorMap[static_cast<int>(FaceCap::BlendshapeCount)] = {    FaceCap::BrowsU_C,    FaceCap::BrowsD_R,    FaceCap::BrowsD_L,    FaceCap::BrowsU_R,    FaceCap::BrowsU_L,    FaceCap::EyeUp_R,    FaceCap::EyeUp_L,    FaceCap::EyeDown_R,    FaceCap::EyeDown_L,    FaceCap::EyeIn_R,    FaceCap::EyeIn_L,    FaceCap::EyeOut_R,    FaceCap::EyeOut_L,    FaceCap::EyeBlink_R,    FaceCap::EyeBlink_L,    FaceCap::EyeSquint_R,    FaceCap::EyeSquint_L,    FaceCap::EyeOpen_R,    FaceCap::EyeOpen_L,    FaceCap::Puff,    FaceCap::CheekSquint_R,    FaceCap::CheekSquint_L,    FaceCap::NoseSneer_R,    FaceCap::NoseSneer_L,    FaceCap::JawOpen,    FaceCap::JawFwd,    FaceCap::JawRight,    FaceCap::JawLeft,    FaceCap::LipsFunnel,    FaceCap::LipsPucker,    FaceCap::MouthRight,    FaceCap::MouthLeft,    FaceCap::LipsUpperClose,    FaceCap::LipsLowerClose,    FaceCap::MouthShrugUpper,    FaceCap::MouthShrugLower,    FaceCap::MouthClose,    FaceCap::MouthSmile_R,    FaceCap::MouthSmile_L,    FaceCap::MouthFrown_R,    FaceCap::MouthFrown_L,    FaceCap::MouthDimple_R,    FaceCap::MouthDimple_L,    FaceCap::MouthUpperUp_R,    FaceCap::MouthUpperUp_L,    FaceCap::MouthLowerDown_R,    FaceCap::MouthLowerDown_L,    FaceCap::MouthPress_R,    FaceCap::MouthPress_L,    FaceCap::LipsStretch_R,    FaceCap::LipsStretch_L,    FaceCap::TongueOut}; static const char* STRINGS[static_cast<int>(FaceCap::BlendshapeCount)] = {    "BrowsU_C",    "BrowsD_L",    "BrowsD_R",    "BrowsU_L",    "BrowsU_R",    "EyeUp_L",    "EyeUp_R",    "EyeDown_L",    "EyeDown_R",    "EyeIn_L",    "EyeIn_R",    "EyeOut_L",    "EyeOut_R",    "EyeBlink_L",    "EyeBlink_R",    "EyeSquint_L",    "EyeSquint_R",    "EyeOpen_L",    "EyeOpen_R",    "Puff",    "CheekSquint_L",    "CheekSquint_R",    "NoseSneer_L",    "NoseSneer_R",    "JawOpen",    "JawFwd",    "JawLeft",    "JawRight",    "LipsFunnel",    "LipsPucker",    "MouthLeft",    "MouthRight",    "LipsUpperClose",    "LipsLowerClose",    "MouthShrugUpper",    "MouthShrugLower",    "MouthClose",    "MouthSmile_L",    "MouthSmile_R",    "MouthFrown_L",    "MouthFrown_R",    "MouthDimple_L",    "MouthDimple_R",    "MouthUpperUp_L",    "MouthUpperUp_R",    "MouthLowerDown_L",    "MouthLowerDown_R",    "MouthPress_L",    "MouthPress_R",    "LipsStretch_L",    "LipsStretch_R",    "TongueOut"}; static enum controller::StandardAxisChannel CHANNELS[static_cast<int>(FaceCap::BlendshapeCount)] = {    controller::BROWSU_C,    controller::BROWSD_L,    controller::BROWSD_R,    controller::BROWSU_L,    controller::BROWSU_R,    controller::EYEUP_L,    controller::EYEUP_R,    controller::EYEDOWN_L,    controller::EYEDOWN_R,    controller::EYEIN_L,    controller::EYEIN_R,    controller::EYEOUT_L,    controller::EYEOUT_R,    controller::EYEBLINK_L,    controller::EYEBLINK_R,    controller::EYESQUINT_L,    controller::EYESQUINT_R,    controller::EYEOPEN_L,    controller::EYEOPEN_R,    controller::PUFF,    controller::CHEEKSQUINT_L,    controller::CHEEKSQUINT_R,    controller::NOSESNEER_L,    controller::NOSESNEER_R,    controller::JAWOPEN,    controller::JAWFWD,    controller::JAWLEFT,    controller::JAWRIGHT,    controller::LIPSFUNNEL,    controller::LIPSPUCKER,    controller::MOUTHLEFT,    controller::MOUTHRIGHT,    controller::LIPSUPPERCLOSE,    controller::LIPSLOWERCLOSE,    controller::MOUTHSHRUGUPPER,    controller::MOUTHSHRUGLOWER,    controller::MOUTHCLOSE,    controller::MOUTHSMILE_L,    controller::MOUTHSMILE_R,    controller::MOUTHFROWN_L,    controller::MOUTHFROWN_R,    controller::MOUTHDIMPLE_L,    controller::MOUTHDIMPLE_R,    controller::MOUTHUPPERUP_L,    controller::MOUTHUPPERUP_R,    controller::MOUTHLOWERDOWN_L,    controller::MOUTHLOWERDOWN_R,    controller::MOUTHPRESS_L,    controller::MOUTHPRESS_R,    controller::LIPSSTRETCH_L,    controller::LIPSSTRETCH_R,    controller::TONGUEOUT};  void OscPlugin::init() {     _inputDevice = std::make_shared<InputDevice>();    _inputDevice->setContainer(this);     {        std::lock_guard<std::mutex> guard(_dataMutex);        _blendshapeValues.assign(static_cast<int>(FaceCap::BlendshapeCount), 0.0f);        _blendshapeValidFlags.assign(static_cast<int>(FaceCap::BlendshapeCount), false);        _headRot = glm::quat();        _headRotValid = false;        _headTransTarget = extractTranslation(_lastInputCalibrationData.defaultHeadMat);        _headTransSmoothed = extractTranslation(_lastInputCalibrationData.defaultHeadMat);        _headTransValid = false;        _eyeLeftRot = glm::quat();        _eyeLeftRotValid = false;        _eyeRightRot = glm::quat();        _eyeRightRotValid = false;    }     loadSettings();     auto preferences = DependencyManager::get<Preferences>();    static const QString OSC_PLUGIN { OscPlugin::NAME };    {        auto getter = [this]()->bool { return _enabled; };        auto setter = [this](bool value) {            _enabled = value;            saveSettings();            if (!_enabled) {                auto userInputMapper = DependencyManager::get<controller::UserInputMapper>();                userInputMapper->withLock([&, this]() {                    _inputDevice->clearState();                    restartServer();                });            }        };        auto preference = new CheckPreference(OSC_PLUGIN, "Enabled", getter, setter);        preferences->addPreference(preference);    }    {        auto debugGetter = [this]()->bool { return _debug; };        auto debugSetter = [this](bool value) {            _debug = value;            saveSettings();        };        auto preference = new CheckPreference(OSC_PLUGIN, "Extra Debugging", debugGetter, debugSetter);        preferences->addPreference(preference);    }     {        static const int MIN_PORT_NUMBER { 0 };        static const int MAX_PORT_NUMBER { 65535 };         auto getter = [this]()->float { return (float)_serverPort; };        auto setter = [this](float value) {            _serverPort = (int)value;            saveSettings();            restartServer();        };        auto preference = new SpinnerPreference(OSC_PLUGIN, "Server Port", getter, setter);         preference->setMin(MIN_PORT_NUMBER);        preference->setMax(MAX_PORT_NUMBER);        preference->setStep(1);        preferences->addPreference(preference);    }} bool OscPlugin::isSupported() const {    // networking/UDP is pretty much always available...    return true;} static void errorHandlerFunc(int num, const char* msg, const char* path) {    qDebug(inputplugins) << "OscPlugin: server error" << num << "in path" << path << ":" << msg;} static int genericHandlerFunc(const char* path, const char* types, lo_arg** argv,                              int argc, lo_message msg, void* user_data) {     OscPlugin* container = reinterpret_cast<OscPlugin*>(user_data);    assert(container);     QString key(path);    std::lock_guard<std::mutex> guard(container->_dataMutex);     // Special case: decode blendshapes from face-cap iPhone app.    // http://www.bannaflak.com/face-cap/livemode.html    if (path[0] == '/' && path[1] == 'W' && argc == 2 && types[0] == 'i' && types[1] == 'f') {        int index = argv[0]->i;        if (index >= 0 && index < static_cast<int>(FaceCap::BlendshapeCount)) {            int mirroredIndex = (int)faceMirrorMap[index];            container->_blendshapeValues[mirroredIndex] = argv[1]->f;            container->_blendshapeValidFlags[mirroredIndex] = true;        }    }     // map /HT to head translation    if (path[0] == '/' && path[1] == 'H' && path[2] == 'T' &&        types[0] == 'f' && types[1] == 'f' && types[2] == 'f') {        glm::vec3 trans(-argv[0]->f, -argv[1]->f, argv[2]->f); // in cm         // convert trans into a delta (in meters) from the sweet spot of the iphone camera.        const float CM_TO_METERS = 0.01f;        const glm::vec3 FACE_CAP_HEAD_SWEET_SPOT(0.0f, 0.0f, -45.0f);        glm::vec3 delta = (trans - FACE_CAP_HEAD_SWEET_SPOT) * CM_TO_METERS;         container->_headTransTarget = extractTranslation(container->_lastInputCalibrationData.defaultHeadMat) + delta;        container->_headTransValid = true;    }     // map /HR to head rotation    if (path[0] == '/' && path[1] == 'H' && path[2] == 'R' && path[3] == 0 &&        types[0] == 'f' && types[1] == 'f' && types[2] == 'f') {        glm::vec3 euler(-argv[0]->f, -argv[1]->f, argv[2]->f);        container->_headRot = glm::quat(glm::radians(euler)) * Quaternions::Y_180;        container->_headRotValid = true;    }     // map /ELR to left eye rot    if (path[0] == '/' && path[1] == 'E' && path[2] == 'L' && path[3] == 'R' &&        types[0] == 'f' && types[1] == 'f') {        glm::vec3 euler(argv[0]->f, -argv[1]->f, 0.0f);        container->_eyeLeftRot = container->_headRot * glm::quat(glm::radians(euler));        container->_eyeLeftRotValid = true;    }     // map /ERR to right eye rot    if (path[0] == '/' && path[1] == 'E' && path[2] == 'R' && path[3] == 'R' &&        types[0] == 'f' && types[1] == 'f') {        glm::vec3 euler((float)argv[0]->f, (float)-argv[1]->f, 0.0f);        container->_eyeRightRot = container->_headRot * glm::quat(glm::radians(euler));        container->_eyeRightRotValid = true;    }     // AJT: TODO map /STRINGS[i] to _blendshapeValues[i]     if (container->_debug) {        for (int i = 0; i < argc; i++) {            switch (types[i]) {            case 'i':                // int32                qDebug(inputplugins) << "OscPlugin: " << path << "[" << i << "] =" << argv[i]->i;                break;            case 'f':                // float32                qDebug(inputplugins) << "OscPlugin: " << path << "[" << i << "] =" << argv[i]->f32;                break;            case 's':                // OSC-string                qDebug(inputplugins) << "OscPlugin: " << path << "[" << i << "] = <string>";                break;            case 'b':                // OSC-blob                break;            case 'h':                // 64 bit big-endian two's complement integer                qDebug(inputplugins) << "OscPlugin: " << path << "[" << i << "] =" << argv[i]->h;                break;            case 't':                // OSC-timetag                qDebug(inputplugins) << "OscPlugin: " << path << "[" << i << "] = <OSC-timetag>";                break;            case 'd':                // 64 bit ("double") IEEE 754 floating point number                qDebug(inputplugins) << "OscPlugin: " << path << "[" << i << "] =" << argv[i]->d;                break;            case 'S':                // Alternate type represented as an OSC-string (for example, for systems that differentiate "symbols" from "strings")                qDebug(inputplugins) << "OscPlugin: " << path << "[" << i << "] = <OSC-symbol>";                break;            case 'c':                // an ascii character, sent as 32 bits                qDebug(inputplugins) << "OscPlugin: " << path << "[" << i << "] =" << argv[i]->c;                break;            case 'r':                // 32 bit RGBA color                qDebug(inputplugins) << "OscPlugin: " << path << "[" << i << "] = <color>";                break;            case 'm':                // 4 byte MIDI message. Bytes from MSB to LSB are: port id, status byte, data1, data2                qDebug(inputplugins) << "OscPlugin: " << path << "[" << i << "] = <midi>";                break;            case 'T':                // true                qDebug(inputplugins) << "OscPlugin: " << path << "[" << i << "] = <true>";                break;            case 'F':                // false                qDebug(inputplugins) << "OscPlugin: " << path << "[" << i << "] = <false>";                break;            case 'N':                // nil                qDebug(inputplugins) << "OscPlugin: " << path << "[" << i << "] = <nil>";                break;            case 'I':                // inf                qDebug(inputplugins) << "OscPlugin: " << path << "[" << i << "] = <inf>";                break;            case '[':                // Indicates the beginning of an array. The tags following are for data in the Array until a close brace tag is reached.                qDebug(inputplugins) << "OscPlugin: " << path << "[" << i << "] = <begin-array>";                break;            case ']':                // Indicates the end of an array.                qDebug(inputplugins) << "OscPlugin: " << path << "[" << i << "] = <end-array>";                break;            default:                qDebug(inputplugins) << "OscPlugin: " << path << "[" << i << "] = <unknown-type>" << types[i];                break;            }        }    }     return 1;}  bool OscPlugin::activate() {    InputPlugin::activate();     loadSettings();     if (_enabled) {         qDebug(inputplugins) << "OscPlugin: activated";         // register with userInputMapper        auto userInputMapper = DependencyManager::get<controller::UserInputMapper>();        userInputMapper->registerDevice(_inputDevice);         return startServer();    }    return false;} void OscPlugin::deactivate() {    qDebug(inputplugins) << "OscPlugin: deactivated, _oscServerThread =" << _oscServerThread;     if (_oscServerThread) {        stopServer();    }} void OscPlugin::pluginUpdate(float deltaTime, const controller::InputCalibrationData& inputCalibrationData) {    if (!_enabled) {

Lines 1–500 of 636.