Compare commits
20 Commits
Author | SHA1 | Date |
---|---|---|
cailean | 0778d1134a | 2 months ago |
cailean | ac632ad4a4 | 2 months ago |
cailean | abbc55cded | 2 months ago |
cailean | 67be65c338 | 3 months ago |
cailean | dc1a0048e3 | 3 months ago |
cailean | 2fe1fc6a69 | 3 months ago |
cailean | 9003780371 | 3 months ago |
cailean | 3ce5ca0c14 | 3 months ago |
cailean | acf3174228 | 3 months ago |
cailean | 1d53af5b0f | 3 months ago |
cailean | b78446bcf7 | 3 months ago |
cailean | 99df9a29fb | 3 months ago |
cailean | d1c91b2ba8 | 3 months ago |
cailean | 589734cce9 | 3 months ago |
cailean | 5788a20a20 | 3 months ago |
cailean | ac3b55d497 | 3 months ago |
cailean | a84c188f0e | 3 months ago |
cailean | d859084ee3 | 3 months ago |
cailean | 5104e7af27 | 3 months ago |
cailean | 4eb21c1fa7 | 3 months ago |
21 changed files with 1204 additions and 123 deletions
@ -0,0 +1,3 @@ |
|||
{ |
|||
"C_Cpp.errorSquiggles": "enabled" |
|||
} |
@ -1,2 +1,12 @@ |
|||
ofxOpenCv |
|||
ofxOpenCv |
|||
ofxOsc |
|||
ofxOsc |
|||
ofxNetwork |
|||
ofxNetwork |
|||
ofxGui |
|||
ofxGui |
|||
ofxTSNE |
|||
ofxTSNE |
|||
ofxPiMapper |
|||
ofxPiMapper |
@ -0,0 +1,282 @@ |
|||
#include "Map.h" |
|||
#include "algorithm" |
|||
|
|||
Map::Map(){ |
|||
|
|||
} |
|||
|
|||
void Map::Setup(){ |
|||
scale = 10000; |
|||
isDebug = true; |
|||
|
|||
json_embeddings = ofLoadJson(jsonPath); |
|||
if(!json_embeddings.is_array()){ |
|||
ofLogError() << "JSON is not an array"; |
|||
return; |
|||
} else { |
|||
std::cout << "JSON LOADED" << std::endl; |
|||
SetupTSNE(); |
|||
} |
|||
|
|||
mapFbo.allocate(ofGetWindowWidth() / 2, ofGetWindowHeight(), GL_RGB); |
|||
|
|||
fboImage.allocate(ofGetWindowWidth() / 2, ofGetWindowHeight(), OF_IMAGE_COLOR); |
|||
|
|||
Setup3D(); |
|||
|
|||
SetupNodes(); |
|||
} |
|||
|
|||
void Map::Update(std::string& vp_img, bool& is_active){ |
|||
time = ofGetElapsedTimef(); |
|||
for(auto& n : nodes){ |
|||
glm::vec2 offset = n.amplitude * sin(n.speed * time); |
|||
n.offset = glm::vec3(offset.x, offset.y, 0); |
|||
} |
|||
std::cout << cam.getPosition() << std::endl; |
|||
if(is_active){ |
|||
has_reached = false; |
|||
} |
|||
|
|||
if(!is_active) |
|||
MoveCamera(vp_img); |
|||
} |
|||
|
|||
void Map::Draw(){ |
|||
mapFbo.begin(); |
|||
|
|||
cam.begin(); |
|||
|
|||
ofClear(0, 0, 0, 1); |
|||
|
|||
ofMatrix4x4 projectionMatrix = cam.getProjectionMatrix(); |
|||
ofMatrix4x4 viewMatrix = cam.getModelViewMatrix(); |
|||
ofMatrix4x4 mvpMatrix = projectionMatrix * viewMatrix; |
|||
|
|||
for (auto& n :sortedNodes){ |
|||
glm::vec3 node_position = n->position + n->offset; |
|||
|
|||
|
|||
if(isFrustum(node_position, 50)){ |
|||
n->texture.getTexture().bind(); |
|||
ofPushMatrix(); |
|||
ofFill(); |
|||
n->geom.setPosition(node_position); |
|||
n->geom.draw(); |
|||
ofPopMatrix(); |
|||
n->texture.getTexture().unbind(); |
|||
} |
|||
|
|||
} |
|||
|
|||
cam.end(); |
|||
|
|||
mapFbo.end(); |
|||
|
|||
mapFbo.readToPixels(fboPixels); |
|||
|
|||
fboImage.setFromPixels(fboPixels); |
|||
} |
|||
|
|||
/*
|
|||
Setup texture for each node |
|||
*/ |
|||
void Map::SetupNodes(){ |
|||
std::cout << "Setting up nodes.." << std::endl; |
|||
for (auto& node : nodes){ |
|||
ofImage img; |
|||
ofPlanePrimitive plane; |
|||
|
|||
img.load("data/" + node.image_path); |
|||
int imageW = img.getWidth() * 0.1; |
|||
int imageH = img.getHeight() * 0.1; |
|||
int maxWidth = 1; |
|||
int maxHeight = 1; |
|||
float aspectRatio = (float)imageW / (float)imageH; |
|||
|
|||
// Determine plane dimensions based on aspect ratio and constraints
|
|||
float planeW, planeH; |
|||
if (aspectRatio > (float)maxWidth / maxHeight) { |
|||
// Image is wider relative to the max constraints
|
|||
planeW = maxWidth; |
|||
planeH = maxWidth / aspectRatio; |
|||
} else { |
|||
// Image is taller relative to the max constraints
|
|||
planeH = maxHeight; |
|||
planeW = maxHeight * aspectRatio; |
|||
} |
|||
|
|||
// Ensure that dimensions do not exceed constraints
|
|||
if (planeH > maxHeight) { |
|||
planeH = maxHeight; |
|||
planeW = maxHeight * aspectRatio; |
|||
} |
|||
if (planeW > maxWidth) { |
|||
planeW = maxWidth; |
|||
planeH = maxWidth / aspectRatio; |
|||
} |
|||
|
|||
plane.set(imageW, imageH); |
|||
plane.setPosition(node.position); |
|||
plane.setResolution(10, 10); |
|||
plane.mapTexCoordsFromTexture(img.getTexture()); |
|||
img.getTexture().setTextureWrap(GL_REPEAT, GL_REPEAT); |
|||
plane.setScale(1); |
|||
|
|||
node.geom = plane; |
|||
node.texture = img; |
|||
node.speed = glm::vec2(ofRandom(0.1, 0.5), ofRandom(0.1, 0.5)); |
|||
node.amplitude = glm::vec2(ofRandom(1, 5), ofRandom(1, 5)); |
|||
node.phase = glm::vec2(ofRandom(0, TWO_PI), ofRandom(0, TWO_PI)); |
|||
} |
|||
std::cout << "Finished setting up nodes!" << std::endl; |
|||
} |
|||
|
|||
/*
|
|||
Setup TSNE - reads JSON, converts to points, creates nodes & hashmap |
|||
*/ |
|||
void Map::SetupTSNE(){ |
|||
for (const auto& entry: json_embeddings) { |
|||
if (entry.contains("vector") && entry["vector"].is_array()) { |
|||
Node n; |
|||
n.foldername = entry["folder"]; |
|||
n.image_path = entry["image"]; |
|||
n.isLost = entry["lost"].get<int>(); |
|||
|
|||
std::vector<float> emb; |
|||
|
|||
for (const auto& value: entry["vector"]){ |
|||
if(value.is_number()){ |
|||
emb.push_back(value.get<float>()); |
|||
} else { |
|||
ofLogError() << "Vector value is not a number"; |
|||
} |
|||
} |
|||
|
|||
n.emotion_vector = emb; |
|||
|
|||
nodes.push_back(n); |
|||
embeddings.push_back(emb); |
|||
} |
|||
} |
|||
|
|||
std::cout << nodes.size() << std::endl; |
|||
|
|||
points = tsne.run(embeddings, dims, perplexity, theta, normalise, runManually); |
|||
|
|||
for (size_t i = 0; i < points.size(); i++){ |
|||
const auto& vec = points[i]; |
|||
auto& n = nodes[i]; |
|||
n.position = (glm::vec3(vec[0] * scale, vec[1] * scale, vec[2] * scale)); |
|||
node_hash_map[n.image_path] = &n; |
|||
} |
|||
|
|||
// Instead of sorting nodes, just create a sorted reference list
|
|||
for (auto& node : nodes) { |
|||
sortedNodes.push_back(&node); // Pointers to the original nodes
|
|||
} |
|||
|
|||
SortNodes(); // Sort the references for rendering
|
|||
} |
|||
|
|||
/*
|
|||
Setup 3D environment |
|||
*/ |
|||
void Map::Setup3D(){ |
|||
cam.setFov(20); |
|||
cam.removeAllInteractions(); |
|||
} |
|||
|
|||
/*
|
|||
Query hashmap |
|||
*/ |
|||
bool Map::SearchMap(std::string& search_string){ |
|||
std::string t = search_string; |
|||
if(node_hash_map.find(t) != node_hash_map.end()){ |
|||
Node* n = node_hash_map[t]; |
|||
std::cout << n->foldername << std::endl; |
|||
return true; |
|||
} else { |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
/* search if image is in the hashmap -> if true, move to its position */ |
|||
void Map::MoveCamera(std::string& vp_img){ |
|||
if(SearchMap(vp_img)){ |
|||
Node* n = node_hash_map[vp_img]; |
|||
glm::vec3 cur_pos(cam.getPosition().x, cam.getPosition().y, cam.getPosition().z); |
|||
glm::vec3 target_pos((n->position.x), (n->position.y), (n->position.z) + 100); |
|||
glm::vec3 dir = target_pos - cur_pos; |
|||
float dist = glm::length(dir); |
|||
dir = glm::normalize(dir); |
|||
accel = dir * 0.02f; |
|||
vel += accel; |
|||
|
|||
// Define minimum and maximum velocities based on distance
|
|||
const float minVelocity = 0.01f; // Minimum velocity when close to the target
|
|||
const float maxVelocityDistance = 1000.0f; // Distance at which max velocity is applied
|
|||
const float maxVelocity = 50.0f; // Maximum velocity
|
|||
|
|||
// Scale max velocity based on distance
|
|||
float dynamicMaxVelocity = glm::clamp(dist / maxVelocityDistance * maxVelocity, minVelocity, maxVelocity); |
|||
|
|||
// Clamp the velocity to the range [-dynamicMaxVelocity, dynamicMaxVelocity]
|
|||
float velocityLength = glm::length(vel); |
|||
if (velocityLength > dynamicMaxVelocity) { |
|||
vel = glm::normalize(vel) * dynamicMaxVelocity; |
|||
} |
|||
|
|||
// Update position
|
|||
glm::vec3 newPosition = cur_pos + vel; |
|||
|
|||
|
|||
if(cam.getPosition() == target_pos){ |
|||
has_reached = true; |
|||
} |
|||
|
|||
if(!has_reached){ |
|||
cam.setPosition(target_pos); |
|||
} |
|||
|
|||
std::cout << "velocity " << vel << std::endl; |
|||
std::cout << "target " << target_pos << std::endl; |
|||
std::cout << "new position " << cam.getPosition() << std::endl; |
|||
} |
|||
|
|||
} |
|||
|
|||
void Map::buttonPressed(int key){ |
|||
if(key==OF_KEY_LEFT){ |
|||
z_adj -= 1; |
|||
} else { |
|||
z_adj += 1; |
|||
} |
|||
} |
|||
|
|||
/*
|
|||
Sort nodes by z position, for draw calls (lowest -> highest) |
|||
*/ |
|||
void Map::SortNodes(){ |
|||
std::sort(sortedNodes.begin(), sortedNodes.end(), [](const Node* a, const Node* b){ |
|||
return a->position.z < b->position.z; // Sorting by z-position
|
|||
}); |
|||
} |
|||
|
|||
bool Map::isFrustum(const glm::vec3& position, float radius){ |
|||
float box_w = 2000; |
|||
float box_h = 2000; |
|||
glm::vec3 cam_position = cam.getPosition(); |
|||
|
|||
float left = cam_position.x - box_w / 2.0f; |
|||
float right = cam_position.x + box_w / 2.0f; |
|||
float top = cam_position.y + box_h / 2.0f; |
|||
float bottom = cam_position.y - box_h / 2.0f; |
|||
|
|||
// Check if the object (with radius) is within the bounding box
|
|||
if (position.x + radius < left || position.x - radius > right) return false; |
|||
if (position.y + radius < bottom || position.y - radius > top) return false; |
|||
|
|||
// Z-depth doesn't matter in this approach, so we're ignoring it
|
|||
return true; |
|||
} |
@ -0,0 +1,87 @@ |
|||
#ifndef _MAP |
|||
#define _MAP |
|||
|
|||
#include "ofMain.h" |
|||
#include "ofxOsc.h" |
|||
#include "ofxTSNE.h" |
|||
|
|||
struct Node { |
|||
glm::vec2 speed; |
|||
glm::vec2 amplitude; |
|||
glm::vec2 phase; |
|||
glm::vec3 offset; |
|||
ofImage texture; |
|||
ofPlanePrimitive geom; |
|||
glm::vec3 position; |
|||
std::string image_path; |
|||
std::string foldername; |
|||
std::vector<float> emotion_vector; |
|||
int isLost; |
|||
}; |
|||
|
|||
class Map { |
|||
public: |
|||
|
|||
/*
|
|||
Methods |
|||
*/ |
|||
|
|||
Map(); |
|||
void Setup(); |
|||
void Update(std::string& vp_img, bool& is_active); |
|||
void Draw(); |
|||
void SetupNodes(); |
|||
void SetupTSNE(); |
|||
void Setup3D(); |
|||
|
|||
bool SearchMap(std::string& search_string); |
|||
void SortNodes(); |
|||
|
|||
void MoveCamera(std::string& vp_img); |
|||
|
|||
bool isFrustum(const glm::vec3& position, float radius); |
|||
|
|||
void buttonPressed(int key); |
|||
|
|||
/*
|
|||
Variables |
|||
*/ |
|||
bool isDebug; |
|||
float time; |
|||
|
|||
ofFbo mapFbo; |
|||
std::vector<Node> nodes; |
|||
std::vector<Node*> sortedNodes; |
|||
float scale; |
|||
|
|||
ofxTSNE tsne; |
|||
vector<vector<double>> points; |
|||
vector<vector<float>> embeddings; |
|||
int dims = 3; |
|||
float perplexity = 20; |
|||
float theta = 0.2; |
|||
bool normalise = true; |
|||
bool runManually = false; |
|||
ofJson json_embeddings; |
|||
std::string jsonPath = "data/json/embeddings.json"; |
|||
|
|||
std::unordered_map<std::string, Node*> node_hash_map; |
|||
|
|||
/*
|
|||
3D Variables |
|||
*/ |
|||
ofLight light; |
|||
ofEasyCam cam; |
|||
float zoom; |
|||
glm::vec3 accel; |
|||
glm::vec3 vel; |
|||
float z_adj = 0; |
|||
bool has_reached = false; |
|||
|
|||
ofImage fboImage; |
|||
ofPixels fboPixels; |
|||
|
|||
private: |
|||
}; |
|||
|
|||
#endif |
@ -0,0 +1,99 @@ |
|||
#include "ofMain.h" |
|||
#include "Onnx.h" |
|||
#include "Yolo.h" |
|||
|
|||
class ModelThread : public ofThread |
|||
{ |
|||
public: |
|||
ofImage* img; |
|||
ofFbo* fbo; |
|||
Onnx* model; |
|||
Yolo* yolo; |
|||
std::vector<types::BoxfWithLandmarks>* detected_faces; |
|||
std::string model_type; |
|||
|
|||
// emotional recognition model
|
|||
std::vector<ofImage>* croppedFaces; |
|||
float* emotional_data; |
|||
|
|||
|
|||
~ModelThread(){ |
|||
stop(); |
|||
waitForThread(false); |
|||
} |
|||
|
|||
void setup(ofImage* _img, ofFbo* _fbo, Onnx* _model){ |
|||
std::lock_guard<std::mutex> lock(mutex); |
|||
this->img = _img; |
|||
this->fbo = _fbo; |
|||
this->model = _model; |
|||
this->model_type = "depth"; |
|||
} |
|||
|
|||
void setupYolo(ofImage* _img, std::vector<types::BoxfWithLandmarks>* _detected_faces, Onnx* _model, Yolo* _yolo){ |
|||
std::lock_guard<std::mutex> lock(mutex); |
|||
this->img = _img; |
|||
this->detected_faces = _detected_faces; |
|||
this->model_type = "yolo"; |
|||
this->model = _model; |
|||
this->yolo = _yolo; |
|||
} |
|||
|
|||
void start(){ |
|||
startThread(); |
|||
} |
|||
|
|||
void stop(){ |
|||
stopThread(); |
|||
condition.notify_all(); |
|||
} |
|||
|
|||
void threadedFunction(){ |
|||
while(isThreadRunning()){ |
|||
if(model_type == "depth"){ |
|||
std::unique_lock<std::mutex> lock(mutex); |
|||
inferDepthImage(fbo, img, model); |
|||
condition.wait(lock); |
|||
} else if(model_type == "yolo") { |
|||
std::unique_lock<std::mutex> lock(mutex); |
|||
inferYolo(); |
|||
condition.wait(lock); |
|||
} |
|||
|
|||
} |
|||
} |
|||
|
|||
void update(){ |
|||
std::lock_guard<std::mutex> lock(mutex); |
|||
condition.notify_one(); |
|||
} |
|||
|
|||
void inferYolo(){ |
|||
auto output_tensors_face = model->Run(*img); |
|||
|
|||
auto output_faces = output_tensors_face.front().GetTensorTypeAndShapeInfo().GetShape(); |
|||
|
|||
unsigned int num_anchors = output_faces[1]; // Number of anchors
|
|||
|
|||
float* output_face_ptr = output_tensors_face.front().GetTensorMutableData<float>(); |
|||
|
|||
yolo->ParseOutput(output_face_ptr, *detected_faces, num_anchors); |
|||
} |
|||
|
|||
void inferDepthImage(ofFbo* fbo, ofImage* img, Onnx* model){ |
|||
auto output_tensors = model->Run(*img); |
|||
float* output_ptr = output_tensors.front().GetTensorMutableData<float>(); |
|||
size_t num_elements = output_tensors.front().GetTensorTypeAndShapeInfo().GetElementCount(); |
|||
|
|||
float min_value = model->ReduceMin(output_ptr, num_elements); |
|||
float max_value = model->ReduceMax(output_ptr, num_elements); |
|||
|
|||
model->Normalize(output_ptr, num_elements, min_value, max_value); |
|||
|
|||
model->DataToFbo(output_ptr, 518, 518, *fbo); |
|||
} |
|||
|
|||
|
|||
protected: |
|||
std::condition_variable condition; |
|||
}; |
@ -0,0 +1,21 @@ |
|||
#include "QuadSource.h" |
|||
|
|||
void QuadSource::setup(){ |
|||
// name
|
|||
name = "test"; |
|||
|
|||
// allocate size
|
|||
allocate(1512, 1080); |
|||
} |
|||
|
|||
|
|||
void QuadSource::update(){ |
|||
|
|||
} |
|||
|
|||
void QuadSource::draw(){ |
|||
// Fill FBO with our quads
|
|||
ofClear(0); |
|||
//ofBackground(255, 120, 10);
|
|||
fbo_in->draw(0, 0); |
|||
} |
@ -0,0 +1,17 @@ |
|||
#ifndef _QUADSOURCE |
|||
#define _QUADSOURCE |
|||
|
|||
#include "ofMain.h" |
|||
#include "FboSource.h" |
|||
|
|||
class QuadSource : public ofx::piMapper::FboSource{ |
|||
|
|||
public: |
|||
void setup(); |
|||
void update(); |
|||
void draw(); |
|||
|
|||
std::vector<ofRectangle> quads; |
|||
std::vector<float> quad_speeds; |
|||
}; |
|||
#endif |
@ -0,0 +1,40 @@ |
|||
#include "Request.h" |
|||
|
|||
/* setup http server */ |
|||
void Request::setup(std::string ip, int port, std::string page){ |
|||
std::cout << "Initialising HTTP Server" << std::endl; |
|||
|
|||
req.method = ofHttpRequest::POST; |
|||
req.url = "http://" + ip + ":" + ofToString(port) + "/" + page; |
|||
req.headers["Content-Type"] = "application/json"; |
|||
} |
|||
|
|||
/* send a request to vp_server & return frame/video/folder */ |
|||
VPResp Request::query(Vector7D& in){ |
|||
VPResp vp_resp; |
|||
try { |
|||
req.body = "{\"vector\": [" + |
|||
ofToString(in.angry) + "," + |
|||
ofToString(in.disgust) + "," + |
|||
ofToString(in.fear) + "," + |
|||
ofToString(in.happy) + "," + |
|||
ofToString(in.sad) + "," + |
|||
ofToString(in.surprise) + "," + |
|||
ofToString(in.neutral) + "]}"; |
|||
|
|||
auto resp = http.handleRequest(req); |
|||
json_resp = ofJson::parse(resp.data.getText()); |
|||
vp_resp.folder = json_resp["folder"]; |
|||
vp_resp.image = json_resp["image"]; |
|||
vp_resp.video = json_resp["video"]; |
|||
vp_resp.frame = json_resp["frame"]; |
|||
vp_resp.lost = json_resp["lost"]; |
|||
|
|||
past_vp_resp = vp_resp; |
|||
|
|||
return vp_resp; |
|||
} catch (exception e) { |
|||
// Some issue happening here when plugging in controllers, or when they initially connect
|
|||
return past_vp_resp; |
|||
} |
|||
} |
@ -0,0 +1,46 @@ |
|||
#ifndef _REQUEST |
|||
#define _REQUEST |
|||
|
|||
#include "ofMain.h" |
|||
|
|||
/* emotional embedding */ |
|||
struct Vector7D { |
|||
float angry; |
|||
float disgust; |
|||
float fear; |
|||
float happy; |
|||
float sad; |
|||
float surprise; |
|||
float neutral; |
|||
|
|||
bool operator!=(const Vector7D &other) const { |
|||
return angry != other.angry || |
|||
disgust != other.disgust || |
|||
fear != other.fear || |
|||
happy != other.happy || |
|||
sad != other.sad || |
|||
surprise != other.surprise || |
|||
neutral != other.neutral; |
|||
} |
|||
}; |
|||
|
|||
/* Vantage point query structure */ |
|||
struct VPResp{ |
|||
std::string folder; |
|||
std::string video; |
|||
std::string image; |
|||
std::string frame; |
|||
int lost; |
|||
}; |
|||
|
|||
class Request{ |
|||
public: |
|||
void setup(std::string ip, int port, std::string page); |
|||
VPResp query(Vector7D& in); |
|||
|
|||
ofHttpRequest req; |
|||
ofURLFileLoader http; |
|||
ofJson json_resp; |
|||
VPResp past_vp_resp; |
|||
}; |
|||
#endif |
@ -0,0 +1,159 @@ |
|||
#include "Server.h" |
|||
|
|||
void Server::start(){ |
|||
std::cout << "Initialising TCP sever" << std::endl; |
|||
server.setup(port); |
|||
osc_sender.setup(OSC_HOST, OSC_PORT); |
|||
http.setup(http_ip, http_port, http_page); |
|||
is_active = true; |
|||
previous_embedding = embedding; |
|||
last_change_time = std::chrono::steady_clock::now(); |
|||
} |
|||
|
|||
void Server::update(){ |
|||
|
|||
for ( int i = 0; i < server.getLastID(); i++){ |
|||
if (server.isClientConnected(i)) { |
|||
const int buffer_size = 8; |
|||
char buffer[buffer_size]; |
|||
int bytes_recieved = server.receiveRawBytes(i, buffer, buffer_size); |
|||
|
|||
if (bytes_recieved == buffer_size){ |
|||
float value; |
|||
int id; |
|||
memcpy(&value, buffer, sizeof(float)); |
|||
memcpy(&id, buffer + sizeof(float), sizeof(int)); |
|||
|
|||
std::string ip_address = server.getClientIP(i); |
|||
|
|||
addOrUpdateClient(id, value, ip_address); |
|||
} |
|||
} |
|||
} |
|||
|
|||
updateEmbedding(); |
|||
checkActivity(); |
|||
sendOSCMessage(); |
|||
|
|||
if(debug){ |
|||
printClients(); |
|||
} |
|||
} |
|||
|
|||
void Server::addOrUpdateClient(int client_id, float value, const std::string& ip_address){ |
|||
ClientInfo client; |
|||
|
|||
client.ip_address = ip_address; |
|||
client.value = value; |
|||
|
|||
clients[client_id] = client; |
|||
} |
|||
|
|||
void Server::updateEmbedding(){ |
|||
for(const auto& c : clients){ |
|||
const ClientInfo& info = c.second; |
|||
float val = std::round(info.value * 100.0f) / 100.0f; |
|||
switch(c.first){ |
|||
case 0: |
|||
embedding.angry = val; |
|||
break; |
|||
case 1: |
|||
embedding.disgust = val; |
|||
break; |
|||
case 2: |
|||
embedding.fear = val; |
|||
break; |
|||
case 3: |
|||
embedding.happy = val; |
|||
break; |
|||
case 4: |
|||
embedding.sad = val; |
|||
break; |
|||
case 5: |
|||
embedding.surprise = val; |
|||
break; |
|||
case 6: |
|||
embedding.neutral = val; |
|||
embedding.fear = ofRandom(0.1, 0.6); |
|||
embedding.angry = ofRandom(0.01, 0.99); |
|||
embedding.happy = ofRandom(0.01, 0.99); |
|||
break; |
|||
} |
|||
} |
|||
} |
|||
|
|||
void Server::printClients(){ |
|||
for( const auto& c : clients){ |
|||
int id = c.first; |
|||
const ClientInfo& info = c.second; |
|||
std::cout << "id: " << id |
|||
<< ", value: " << info.value |
|||
<< ", IP: " << info.ip_address << std::endl; |
|||
} |
|||
|
|||
std::cout << is_active << std::endl; |
|||
} |
|||
|
|||
/* check if the controllers are in use */ |
|||
void Server::checkActivity(){ |
|||
if (previous_embedding.neutral != embedding.neutral) { // Check if embedding has changed
|
|||
last_change_time = std::chrono::steady_clock::now(); // Reset the timer if there is a change
|
|||
previous_embedding = embedding; // Update the previous embedding to the current one
|
|||
is_active = true; |
|||
sendHttpRequest(); |
|||
} else { |
|||
// Calculate the time since the last change
|
|||
auto now = std::chrono::steady_clock::now(); |
|||
auto duration = std::chrono::duration_cast<std::chrono::seconds>(now - last_change_time).count(); |
|||
|
|||
if (duration >= 2) { |
|||
is_active = false; |
|||
} |
|||
} |
|||
} |
|||
|
|||
/* send osc msg, check if audio file exists and it is different to the past audiofile */ |
|||
void Server::sendOSCMessage(){ |
|||
std::vector<ofxOscMessage> messages; |
|||
|
|||
ofxOscMessage me_0; |
|||
ofxOscMessage me_1; |
|||
ofxOscMessage me_2; |
|||
ofxOscMessage me_3; |
|||
ofxOscMessage me_file; |
|||
|
|||
std::string audio_file = vp_resp.folder; |
|||
|
|||
// Check if file exists in a given dir
|
|||
ofFile file("/home/cailean/Desktop/rave/all_wav_files/" + audio_file + ".wav"); |
|||
|
|||
if(!is_active && (audio_file != past_audio_file) && file.exists()){ |
|||
me_file.setAddress("/emote/filename"); |
|||
me_file.addStringArg(audio_file + ".wav"); |
|||
messages.push_back(me_file); |
|||
past_audio_file = audio_file; |
|||
} |
|||
|
|||
me_0.setAddress("/emote/0"); |
|||
me_0.addFloatArg(embedding.neutral); |
|||
messages.push_back(me_0); |
|||
me_1.setAddress("/emote/1"); |
|||
me_1.addFloatArg(embedding.neutral); |
|||
messages.push_back(me_1); |
|||
me_2.setAddress("/emote/2"); |
|||
me_2.addFloatArg(embedding.neutral); |
|||
messages.push_back(me_2); |
|||
me_3.setAddress("/emote/3"); |
|||
me_3.addFloatArg(embedding.neutral); |
|||
messages.push_back(me_3); |
|||
|
|||
for (auto& msg : messages){ |
|||
osc_sender.sendMessage(msg, false); |
|||
} |
|||
|
|||
} |
|||
|
|||
/* sends request to http server if is_active = true */ |
|||
void Server::sendHttpRequest(){ |
|||
vp_resp = http.query(embedding); |
|||
} |
@ -0,0 +1,54 @@ |
|||
#ifndef _SERVER |
|||
#define _SERVER |
|||
|
|||
#include "ofMain.h" |
|||
#include "ofxNetwork.h" |
|||
#include "Request.h" |
|||
#include <unordered_map> |
|||
#include <chrono> |
|||
#include "ofxOsc.h" |
|||
|
|||
#define OSC_HOST "127.0.0.1" |
|||
#define OSC_PORT 9002 |
|||
|
|||
struct ClientInfo { |
|||
float value; |
|||
std::string ip_address; |
|||
}; |
|||
|
|||
class Server{ |
|||
public: |
|||
Server(int port, Vector7D& _embedding, bool debug, std::string _http_ip, int _http_port, std::string _http_page) |
|||
: port(port), embedding(_embedding), debug(debug), http_ip(_http_ip), http_port(_http_port), http_page(_http_page) {} |
|||
|
|||
void start(); |
|||
void update(); |
|||
void addOrUpdateClient(int client_id, float value, const std::string& ip_address); |
|||
void printClients(); |
|||
void updateEmbedding(); |
|||
void checkActivity(); |
|||
void sendHttpRequest(); |
|||
void sendOSCMessage(); |
|||
|
|||
int port; |
|||
ofxTCPServer server; |
|||
std::unordered_map<int, ClientInfo> clients; |
|||
bool debug; |
|||
bool is_active; |
|||
Vector7D& embedding; |
|||
|
|||
Request http; |
|||
std::string http_ip; |
|||
int http_port; |
|||
std::string http_page; |
|||
VPResp vp_resp; |
|||
|
|||
private: |
|||
Vector7D previous_embedding; |
|||
std::chrono::time_point<std::chrono::steady_clock> last_change_time; |
|||
|
|||
ofxOscSender osc_sender; |
|||
std::string past_audio_file; |
|||
}; |
|||
|
|||
#endif |
Loading…
Reference in new issue