From 53a3d1f8c9690a606de9a486043bdf5c59eae89d Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Tue, 12 Feb 2013 23:27:36 -0800 Subject: [PATCH] Added audio waveform oscilloscope, fixing head rendering of other agents and self. --- interface/src/Agent.cpp | 19 ++++++--- interface/src/Agent.h | 5 ++- interface/src/Audio.cpp | 18 +++++++-- interface/src/Audio.h | 6 ++- interface/src/AudioData.cpp | 5 +++ interface/src/Cube.cpp | 2 - interface/src/Head.cpp | 17 +------- interface/src/Oscilloscope.cpp | 14 ++++--- interface/src/Oscilloscope.h | 9 +++-- interface/src/main.cpp | 74 ++++++++++++++++------------------ interface/src/world.h | 1 + 11 files changed, 92 insertions(+), 78 deletions(-) diff --git a/interface/src/Agent.cpp b/interface/src/Agent.cpp index d32837f26e..1feaa63703 100644 --- a/interface/src/Agent.cpp +++ b/interface/src/Agent.cpp @@ -21,6 +21,7 @@ struct AgentList { timeval pingStarted; int pingMsecs; char agentType; + bool isSelf; Head head; } agents[MAX_AGENTS]; @@ -55,12 +56,15 @@ int update_agents(char * data, int length) { return numAgents; } -void render_agents() { +// Render the heads of the agents +void render_agents(int renderSelf) { for (int i = 0; i < num_agents; i++) { glm::vec3 pos = agents[i].head.getPos(); glPushMatrix(); - glTranslatef(pos.x, pos.y, pos.z); - agents[i].head.render(0); + if (!agents[i].isSelf || renderSelf) { + glTranslatef(-pos.x, -pos.y, -pos.z); + agents[i].head.render(0); + } glPopMatrix(); } } @@ -75,6 +79,9 @@ void update_agent(char * address, unsigned short port, char * data, int length) if ((strcmp(address, agents[i].address) == 0) && (agents[i].port == port)) { // Update the agent agents[i].head.recvBroadcastData(data, length); + if ((strcmp(address, "127.0.0.1") == 0) && (port == AGENT_UDP_PORT)) { + agents[i].isSelf = true; + } else agents[i].isSelf = false; } } } @@ -107,14 +114,16 @@ int add_agent(char * address, unsigned short port, char agentType) { // // Broadcast data to all the other agents you are aware of, returns 1 if success // -int broadcastToAgents(UDPSocket *handle, char * data, int length) { +int broadcastToAgents(UDPSocket *handle, char * data, int length, int sendToSelf) { int sent_bytes; //printf("broadcasting to %d agents\n", num_agents); for (int i = 0; i < num_agents; i++) { //std::cout << "to: Agent address " << agents[i].address << " port " << agents[i].port << "\n"; + if (sendToSelf || ((strcmp((char *)"127.0.0.1", agents[i].address) != 0) + && (agents[i].port != AGENT_UDP_PORT))) sent_bytes = handle->send(agents[i].address, agents[i].port, data, length); if (sent_bytes != length) { - std::cout << "Broadcast packet fail!\n"; + std::cout << "Broadcast to agents FAILED\n"; return 0; } } diff --git a/interface/src/Agent.h b/interface/src/Agent.h index 305864aa43..5542388aba 100644 --- a/interface/src/Agent.h +++ b/interface/src/Agent.h @@ -18,13 +18,14 @@ #include #include "UDPSocket.h" +const int AGENT_UDP_PORT = 40103; int update_agents(char * data, int length); int add_agent(char * address, unsigned short port, char agentType); -int broadcastToAgents(UDPSocket * handle, char * data, int length); +int broadcastToAgents(UDPSocket * handle, char * data, int length, int sendToSelf); void pingAgents(UDPSocket *handle); void setAgentPing(char * address, unsigned short port); void update_agent(char * address, unsigned short port, char * data, int length); -void render_agents(); +void render_agents(int renderSelf); #endif diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 949b79efe3..9614d740ca 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -17,6 +17,8 @@ #include "AudioSource.h" #include "UDPSocket.h" +Oscilloscope * scope; + const short BUFFER_LENGTH_BYTES = 1024; const short BUFFER_LENGTH_SAMPLES = BUFFER_LENGTH_BYTES / sizeof(int16_t); @@ -97,6 +99,14 @@ int audioCallback (const void *inputBuffer, loudness /= BUFFER_LENGTH_SAMPLES; data->lastInputLoudness = loudness; data->averagedInputLoudness = 0.66*data->averagedInputLoudness + 0.33*loudness; + // + // If scope is turned on, copy input buffer to scope + // + if (scope->getState()) { + for (int i = 0; i < BUFFER_LENGTH_SAMPLES; i++) { + scope->addData((float)inputLeft[i]/32767.0, i); + } + } } int16_t *outputLeft = ((int16_t **) outputBuffer)[0]; @@ -299,17 +309,19 @@ void *receiveAudioViaUDP(void *args) { * @return Returns true if successful or false if an error occurred. Use Audio::getError() to retrieve the error code. */ -bool Audio::init() +bool Audio::init(Oscilloscope * s) { Head *deadHead = new Head(); - return Audio::init(deadHead); + return Audio::init(deadHead, s); } -bool Audio::init(Head *mainHead) +bool Audio::init(Head *mainHead, Oscilloscope * s) { err = Pa_Initialize(); if (err != paNoError) goto error; + scope = s; + if (ECHO_SERVER_TEST) { data = new AudioData(BUFFER_LENGTH_BYTES); diff --git a/interface/src/Audio.h b/interface/src/Audio.h index 001fb622f4..be6460ebe0 100644 --- a/interface/src/Audio.h +++ b/interface/src/Audio.h @@ -13,12 +13,13 @@ #include #include "Head.h" #include "AudioData.h" +#include "Oscilloscope.h" class Audio { public: // initializes audio I/O - static bool init(); - static bool init(Head* mainHead); + static bool init(Oscilloscope * s); + static bool init(Head* mainHead, Oscilloscope * s); static void render(); static void render(int screenWidth, int screenHeight); @@ -32,6 +33,7 @@ private: static AudioData *data; + // protects constructor so that public init method is used Audio(); diff --git a/interface/src/AudioData.cpp b/interface/src/AudioData.cpp index 0745a045b5..32416a402a 100644 --- a/interface/src/AudioData.cpp +++ b/interface/src/AudioData.cpp @@ -12,6 +12,11 @@ AudioData::AudioData(int bufferLength) { sources = NULL; samplesToQueue = new int16_t[bufferLength / sizeof(int16_t)]; + averagedLatency = 0.0; + lastCallback.tv_usec = 0; + wasStarved = 0; + measuredJitter = 0; + jitterBuffer = 0; } AudioData::AudioData(int numberOfSources, int bufferLength) { diff --git a/interface/src/Cube.cpp b/interface/src/Cube.cpp index 6dee84a0a1..5b093016e3 100644 --- a/interface/src/Cube.cpp +++ b/interface/src/Cube.cpp @@ -59,7 +59,6 @@ VoxelSystem::VoxelSystem(int num, } void VoxelSystem::render() { - glPushMatrix(); int i = 0; while (i < cube_count) { glPushMatrix(); @@ -69,7 +68,6 @@ void VoxelSystem::render() { glPopMatrix(); i++; } - glPopMatrix(); } void VoxelSystem::simulate(float deltaTime) { diff --git a/interface/src/Head.cpp b/interface/src/Head.cpp index 09a9d0af45..34e1e28e9b 100644 --- a/interface/src/Head.cpp +++ b/interface/src/Head.cpp @@ -214,22 +214,7 @@ void Head::render(int faceToFace) glPushMatrix(); glScalef(scale, scale, scale); - glTranslatef(leanSideways, 0.f, leanForward); - - if (!faceToFace) - { - //printf("x: %3.1f\n", position.x); - //glTranslatef(3,3,2); - //printf("head: %3.1f, %3.1f, %3.1f\n", position.x, position.y, position.z); - float x = position.x; - float y = position.y; - float z = position.z; - - //glTranslatef(6.1, 0, 1.4); - glTranslatef(x,y,z); - //glTranslatef(position.x, position.y, position.z); - } glRotatef(Yaw/2.0, 0, 1, 0); glRotatef(Pitch/2.0, 1, 0, 0); @@ -237,7 +222,7 @@ void Head::render(int faceToFace) // Overall scale of head - glScalef(1.5, 2.0, 2.0); + if (faceToFace) glScalef(1.5, 2.0, 2.0); glColor3fv(skinColor); // Head diff --git a/interface/src/Oscilloscope.cpp b/interface/src/Oscilloscope.cpp index d06b263ebe..f5c90da4b2 100644 --- a/interface/src/Oscilloscope.cpp +++ b/interface/src/Oscilloscope.cpp @@ -9,22 +9,26 @@ #include "Oscilloscope.h" Oscilloscope::Oscilloscope(int w, - int h) { + int h, bool isOn) { width = w; height = h; data = new float[width]; for (int i = 0; i < width; i++) { data[i] = 0.0; } + state = isOn; current_sample = 0; } -void Oscilloscope::addData(float d) { - data[current_sample++] = d; +void Oscilloscope::addData(float d, int position) { + data[position] = d; } -void Oscilloscope::render() { +void Oscilloscope::render(float r, float g, float b) { + glColor3f(r,g,b); glBegin(GL_LINES); - //glVertex2f( + for (int i = 0; i < width; i++) { + glVertex2f((float)i, height/2 + data[i]*(float)height); + } glEnd(); } \ No newline at end of file diff --git a/interface/src/Oscilloscope.h b/interface/src/Oscilloscope.h index b86565f6fd..6bbeed2a54 100644 --- a/interface/src/Oscilloscope.h +++ b/interface/src/Oscilloscope.h @@ -18,13 +18,16 @@ class Oscilloscope { public: Oscilloscope(int width, - int height); - void addData(float data); - void render(); + int height, bool isOn); + void addData(float d, int position); + void render(float r, float g, float b); + void setState(bool s) {state = s;}; + bool getState() {return state;}; private: int width; int height; float * data; int current_sample; + bool state; }; #endif /* defined(__interface__oscilloscope__) */ diff --git a/interface/src/main.cpp b/interface/src/main.cpp index 07528e785a..4058575205 100644 --- a/interface/src/main.cpp +++ b/interface/src/main.cpp @@ -44,6 +44,7 @@ #include "Cube.h" #include "Lattice.h" #include "Finger.h" +#include "Oscilloscope.h" using namespace std; @@ -55,7 +56,6 @@ int simulate_on = 1; // const int MAX_PACKET_SIZE = 1500; -const int AGENT_UDP_PORT = 40103; char DOMAINSERVER_IP[] = "127.0.0.1"; const int DOMAINSERVER_PORT = 40102; UDPSocket agentSocket(AGENT_UDP_PORT); @@ -73,15 +73,16 @@ int target_x, target_y; int target_display = 0; int head_mirror = 1; // Whether to mirror own head when viewing it +int sendToSelf = 0; int WIDTH = 1200; int HEIGHT = 800; -int fullscreen = 0; +int fullscreen = 0; + +Oscilloscope audioScope(512,200,false); #define HAND_RADIUS 0.25 // Radius of in-world 'hand' of you -Head myHead; // The rendered head of oneself or others -Head dummyHead; // Test Head to render -int showDummyHead = 0; +Head myHead; // The rendered head of oneself Hand myHand(HAND_RADIUS, glm::vec3(0,1,1)); // My hand (used to manipulate things in world) @@ -301,18 +302,11 @@ void init(void) { myHead.setRenderYaw(start_yaw); - dummyHead.setPitch(0); - dummyHead.setRoll(0); - dummyHead.setYaw(0); - dummyHead.setScale(0.25); - - dummyHead.setPos(glm::vec3(0,0,0)); - if (audio_on) { if (serial_on) { - Audio::init(&myHead); + Audio::init(&myHead, &audioScope); } else { - Audio::init(); + Audio::init(&audioScope); } printf( "Audio started.\n" ); } @@ -330,7 +324,6 @@ void init(void) { myHand.setNoise(noise); myHead.setNoise(noise); - dummyHead.setNoise(noise); } if (serial_on) @@ -387,8 +380,6 @@ void reset_sensors() // Reset serial I/O sensors // myHead.setRenderYaw(start_yaw); - dummyHead.setRenderPitch(0); - dummyHead.setRenderYaw(0); yaw = render_yaw_rate = 0; pitch = render_pitch = render_pitch_rate = 0; @@ -537,16 +528,10 @@ void update_pos(float frametime) myHead.setAverageLoudness(averageLoudness); // Send my streaming head data to agents that are nearby and need to see it! - const int MAX_BROADCAST_STRING = 200; char broadcast_string[MAX_BROADCAST_STRING]; int broadcast_bytes = myHead.getBroadcastData(broadcast_string); - broadcastToAgents(&agentSocket, broadcast_string, broadcast_bytes); - - //printf("-> %s\n", broadcast_string); - //dummyHead.recvBroadcastData(broadcast_string, broadcast_bytes); - //printf("head bytes: %d\n", broadcast_bytes); - + broadcastToAgents(&agentSocket, broadcast_string, broadcast_bytes, sendToSelf); } int render_test_spot = WIDTH/2; @@ -561,6 +546,8 @@ void display(void) glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); + + // Setup 3D lights glEnable(GL_COLOR_MATERIAL); glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE); @@ -591,21 +578,9 @@ void display(void) // Draw field vectors if (display_field) field.render(); - - // Render my own head - if (display_head) { - glPushMatrix(); - glLoadIdentity(); - glTranslatef(0.f, 0.f, -7.f); - myHead.render(1); - glPopMatrix(); - } - - // Render dummy head - if (showDummyHead) dummyHead.render(0); - + // Render heads of other agents - if (!display_head) render_agents(); + render_agents(sendToSelf); if (display_hand) myHand.render(); @@ -614,11 +589,22 @@ void display(void) // Render the world box if (!display_head && stats_on) render_world_box(); + // Render my own head + + if (display_head) { + glPushMatrix(); + glLoadIdentity(); + glTranslatef(0.f, 0.f, -7.f); + myHead.render(1); + glPopMatrix(); + } + // render audio sources and start them if (audio_on) { Audio::render(); } + //glm::vec3 test(0.5, 0.5, 0.5); //render_vector(&test); @@ -635,6 +621,8 @@ void display(void) // lattice.render(WIDTH, HEIGHT); // myFinger.render(); Audio::render(WIDTH, HEIGHT); + if (audioScope.getState()) audioScope.render(0,1,0); + //drawvec3(100, 100, 0.15, 0, 1.0, 0, myHead.getPos(), 0, 1, 0); glPointParameterfvARB( GL_POINT_DISTANCE_ATTENUATION_ARB, pointer_attenuation_quadratic ); @@ -831,7 +819,10 @@ void read_network() // update_agent(inet_ntoa(senderAddress.sin_addr), ntohs(senderAddress.sin_port), &incoming_packet[1], bytes_recvd - 1); } else if (incoming_packet[0] == 'T') { - printf("Got test! From port %d\n", senderAddress.sin_port); + // Received a self-test packet (to get one's own IP), copy it to local variable! + printf("My Address: %s:%u\n", + inet_ntoa(senderAddress.sin_addr), + senderAddress.sin_port); } } } @@ -950,7 +941,10 @@ int main(int argc, char** argv) // Create network socket and buffer incoming_packet = new char[MAX_PACKET_SIZE]; - // + // Send one test packet to detect own IP, port: + char selfTest[] = "T"; + agentSocket.send((char *)"127.0.0.1", AGENT_UDP_PORT, selfTest, 1); + printf("Testing stats math... "); StDev stdevtest; stdevtest.reset(); diff --git a/interface/src/world.h b/interface/src/world.h index a832c29b67..0f93a2258b 100644 --- a/interface/src/world.h +++ b/interface/src/world.h @@ -11,6 +11,7 @@ #ifndef __interface__world__ #define __interface__world__ + const float WORLD_SIZE = 10.0; #define PI 3.14159265