// crtsine.cpp STK tutorial program #include "RtAudio.h" #include #include #include #include #include //includes for OSC messages #include "osc/OscReceivedElements.h" #include "osc/OscPacketListener.h" #include "ip/UdpSocket.h" //threads #include "thread/util_thread.h" //graphics #include "FFT/chuck_fft.h" #include "GL/glut.h" //stk and waveread #include "stk_waveread/Stk.h" #include "stk_waveread/FileWvIn.h" #include "stk_waveread/BiQuad.h" #include "stk_waveread/Noise.h" using namespace stk; using namespace std; #define SAMPLE float //defined as float instead of double becasue chuck_fft uses float #define MY_PIE 3.14159265358979 #define MY_SRATE 44100 //samples per second #define MAX_VELOCITY 127 #define TEMPO 60 //defines for OSC messages #define PORT 7000 #define MAX_OSC 1000 //defines for fft processing #define W_RECT 0 #define W_HAMMING 1 #define W_HANNING 2 #define W_BLACKMAN 3 //defines for graphics #define NUM_WATERFALLS 16 #define SIZE_HISTORY 32 #define POWER_WINDOW 50 #define POWER_RESOLUTION 128 #define POWER_THRESHOLD_MAX 1.1 #define POWER_THRESHOLD_MIN .4 #define SPHERE_SCALE 8 //this gives the x,y range for the sphere #define NUM_SPHERE 4 //this gives the number of following history spheres #define SPHERE_HISTORY 16 //this gives the number of history steps stored for the history spheres #define SPHERE_RADIUS 1 //this gives the starting radius of the first sphere #define RADIUS_MOD .75 //this gives the % of radius reduction for history spheres #define VOLUME_SCALE 1 //this knocks down the output volume to remove clipping struct midi_note_start { int note_num; //a MIDI note between 21 and 108 int velocity; //the volume that the note should be played at, between 0 and 127 float startBeat; //a number in beats at the current tempo }; struct midi_note_stop { int note_num; //a MIDI note bewteen 21 and 108 float stopBeat; //a number in beats at the current tempo }; struct userdata { int tempo; //the tempo in beats per minute }; struct filterAvatar { float coordx; float coordy; vector controllers; bool _on; filterAvatar() { coordx = 500; coordy = 500; _on = false; } }; class interactor { private: string username; public: float rotValXY; float rotValXZ; float rotValYZ; float sphereX [SPHERE_HISTORY]; float sphereY [SPHERE_HISTORY]; float sphereZ [SPHERE_HISTORY]; int sphereCurrX; int sphereCurrY; int sphereCurrZ; float sphereColor; float biquad_freq; float biquad_width; int filterCtrl; int VolumeCtrl; //public: interactor() { this->rotValXY = 0; this->rotValXZ = 0; this->rotValYZ = 0; this->sphereColor = 0; this->biquad_freq = 880; this->biquad_width = .95; this->filterCtrl = -1; this->sphereCurrX = 0; this->sphereCurrY = 0; this->sphereCurrZ = 0; }; interactor(string thename) { this->username = thename; this->rotValXY = 0; this->rotValXZ = 0; this->rotValYZ = 0; this->sphereColor = 0; }; string GetName() const { return this->username; }; /* bool static compare(string first, string second) { return ( first.compare(second) < 0 ); };*/ }; //globals for audio SAMPLE g_t = 0; //this variable keeps track of number of samples since the program started running (more or less) int g_t2 = 0; //this variable tracks the position in non-real-time audio. int g_t2_max = 0; //this tracks the size of the not real-time audio input in samples int exitNum = 0; //for debugging delay buffers // file in FileWvIn g_fin; //globals for visuals // width and height of the window GLsizei g_width = 800; GLsizei g_height = 600; SAMPLE * g_signalHistory[SIZE_HISTORY]; //number of buffers to store for the history int g_curPosHistory; //this keeps track of where we are in the signalHistory array; SAMPLE * g_powerHistory[SIZE_HISTORY]; //number of buffers to store for the history SAMPLE * g_buffer_FFT[NUM_WATERFALLS]; //for the waterfall need history of buffers SAMPLE * g_buffer_windowed; int curPosFFT; //this keeps track of where we are in the FFT array. long g_bufferSize; // size of buffer in samples //g_messageTriggered tracks if an OSC was sent recently so we don't resend messages bool g_messageTriggered = false; //global for interactors in the audience //setup map to hold each interactor map g_audience; int g_userInteractors = 1; //stk and waveread //filters BiQuad g_biquad; filterAvatar g_biquad_avatar; //function for debugging int g_print = 0; void exit_func() { string line; cout << "enter any text and return to exit..." << endl; cin >> line; exit(1); } //function prototypes void GraphicsProcessing( SAMPLE * buffy, int buffer_size ); inline SAMPLE BiquadFreq (SAMPLE base); inline SAMPLE BiquadWidth (SAMPLE base); int MyModulo( int num, int mod ); // This tick() function handles sample computation only. It will be // called automatically when the system needs a new buffer of audio // samples. int tick( void *outputBuffer, void *inputBuffer, unsigned int nBufferFrames, double streamTime, RtAudioStreamStatus status, void *dataPointer ) { register StkFloat * in = (StkFloat *) inputBuffer; register StkFloat * out = (StkFloat *) outputBuffer; float * myOut = new float[nBufferFrames]; /* int counterA = 0; float xcoord = 0; float ycoord = 0; map::iterator iter; for( iter = g_audience.begin(); iter != g_audience.end(); iter++ ) { if( iter->second.filterCtrl == 1 ) { xcoord += BiquadWidth( iter->second.biquad_width ); ycoord += BiquadFreq( -iter->second.biquad_freq ); counterA++; } } if(counterA != 0 ) { xcoord = xcoord / counterA; ycoord = ycoord / counterA; }*/ float xcoord = BiquadWidth( g_biquad_avatar.coordx ); float ycoord = BiquadFreq( g_biquad_avatar.coordy ); g_biquad.setResonance ( ycoord, xcoord, true ); //automatically normalize for unity peak gain for ( unsigned int i=0; i messageParsed; int startSlash = message.find_first_of('/',0); int endSlash = message.find_first_of('/',1); while(startSlash != string::npos) { messageParsed.push(message.substr(startSlash, endSlash - startSlash)); startSlash = endSlash; endSlash = message.find_first_of('/',startSlash + 1); } //navigate parsed message if( !messageParsed.front().compare("/mrmr") ) { messageParsed.pop(); //remove "/mrmr" if( !messageParsed.front().compare("/pushbutton") ) { messageParsed.pop(); //remove "/pushbutton" if( !messageParsed.front().compare("/36") ) { messageParsed.pop(); //remove "/36" if( g_audience[messageParsed.front()].filterCtrl == 1 ) g_audience[messageParsed.front()].filterCtrl = -1; else g_audience[messageParsed.front()].filterCtrl = 1; cout << " " << g_audience[messageParsed.front()].filterCtrl; } else if( !messageParsed.front().compare("/37") ) { messageParsed.pop(); //remove "/37" if( g_audience[messageParsed.front()].filterCtrl == 2 ) g_audience[messageParsed.front()].filterCtrl = -1; else g_audience[messageParsed.front()].filterCtrl = 2; } else if( !messageParsed.front().compare("/38") ) { messageParsed.pop(); //remove "/37" if( g_audience[messageParsed.front()].filterCtrl == 3 ) g_audience[messageParsed.front()].filterCtrl = -1; else g_audience[messageParsed.front()].filterCtrl = 3; } else if( !messageParsed.front().compare("/39") ) { messageParsed.pop(); //remove "/37" if( g_audience[messageParsed.front()].filterCtrl == 4 ) g_audience[messageParsed.front()].filterCtrl = -1; else g_audience[messageParsed.front()].filterCtrl = 4; } } else if( !messageParsed.front().compare("/slider") ) { messageParsed.pop(); //remove /slider messageParsed.pop(); //remove /horizontal or vertical if( !messageParsed.front().compare("/40") ) { messageParsed.pop(); //remove "/40" osc::ReceivedMessageArgumentStream args = m.ArgumentStream(); osc::int32 a1; args >> a1 >> osc::EndMessage; g_audience[messageParsed.front()].rotValXY = (float)(a1 - MAX_OSC/2)/(MAX_OSC/4); } else if( !messageParsed.front().compare("/41") ) { messageParsed.pop(); //remove "/41" osc::ReceivedMessageArgumentStream args = m.ArgumentStream(); osc::int32 a1; args >> a1 >> osc::EndMessage; g_audience[messageParsed.front()].rotValXZ = (float)(a1 - MAX_OSC/2)/(MAX_OSC/4); } else if( !messageParsed.front().compare("/42") ) { messageParsed.pop(); //remove "/42" osc::ReceivedMessageArgumentStream args = m.ArgumentStream(); osc::int32 a1; args >> a1 >> osc::EndMessage; g_audience[messageParsed.front()].rotValYZ = (float)(a1 - MAX_OSC/2)/(MAX_OSC/4); } else if( !messageParsed.front().compare("/43") ) { messageParsed.pop(); //remove "/43" osc::ReceivedMessageArgumentStream args = m.ArgumentStream(); osc::int32 a1; args >> a1 >> osc::EndMessage; g_audience[messageParsed.front()].sphereColor = (float)a1/(float)(MAX_OSC/(2*MY_PIE)); } } else if( !messageParsed.front().compare("/tactilezoneX") ) { osc::ReceivedMessageArgumentStream args = m.ArgumentStream(); osc::int32 a1; args >> a1 >> osc::EndMessage; if( a1 > 1000 ) a1 = 1000; //get audience name messageParsed.pop(); //remove "/tactilezoneX" messageParsed.pop(); //remove "/44" interactor * currPerson = &g_audience[messageParsed.front()]; currPerson->sphereCurrX = (currPerson->sphereCurrX + 1 )%SPHERE_HISTORY; currPerson->sphereX[currPerson->sphereCurrX] = SPHERE_SCALE*((float)(a1-MAX_OSC/2)/MAX_OSC); /* //TODO: this is super in-efficient and slowing down the osc input. need to be changed for( int i = SPHERE_HISTORY - 1; i > 0; i--) { currPerson->sphereX[i] = currPerson->sphereX[i-1]; } currPerson->sphereX[0] = SPHERE_SCALE*((float)(a1-MAX_OSC/2)/MAX_OSC); */ //filter parameters currPerson->biquad_width = a1; // g_biquad_width = .75 + .25 * (a1-500)/500; } if( !messageParsed.front().compare("/tactilezoneY") ) { osc::ReceivedMessageArgumentStream args = m.ArgumentStream(); osc::int32 a1; args >> a1 >> osc::EndMessage; if( a1 > 1000 ) a1 = 1000; //get to audience name messageParsed.pop(); //remove "/tactilezoneY" messageParsed.pop(); //remove "/44" interactor * currPerson = &g_audience[messageParsed.front()]; // currPerson->sphereCurrY = MyModulo( currPerson->sphereCurrY + 1, SPHERE_HISTORY ); currPerson->sphereCurrY = (currPerson->sphereCurrY + 1 )%SPHERE_HISTORY; currPerson->sphereY[currPerson->sphereCurrY] = -SPHERE_SCALE*((float)(a1-MAX_OSC/2)/MAX_OSC); //fitler parameters currPerson->biquad_freq = a1; } } }catch( osc::Exception& e ){ // any parsing errors such as unexpected argument types, or // missing arguments get thrown as exceptions. std::cout << "error while parsing message: " << m.AddressPattern() << ": " << e.what() << "\n"; } } }; unsigned __stdcall oscListener ( void * data) { //create the OSC listener ExamplePacketListener listener; UdpListeningReceiveSocket s( IpEndpointName( IpEndpointName::ANY_ADDRESS, PORT ), &listener ); cout << "OSC listener started: " << PORT << "..." << endl; //starts the socket listening for messages s.RunUntilSigInt(); return NULL; } //takes in an integer between 0 and 1000 and returns a viable biquad width parameter inline SAMPLE BiquadWidth (SAMPLE base ) { return .74 + .25 * ( base -500)/500 ; } //takes in a base integer between 0 and 1000 and returns a viable biquad width parameter inline SAMPLE BiquadFreq (SAMPLE base) { return 220 + 4*base; } //takes in a base integer betwen 0 and 1000 and makes it a viable x coordinate inline SAMPLE BaseCoordX ( SAMPLE base ) { return SPHERE_SCALE*((float)( base -MAX_OSC/2)/MAX_OSC); } //takes in a base inteer between 0 and 1000 and makes it a viable y coordinate inline SAMPLE BaseCoordY ( SAMPLE base ) { return -SPHERE_SCALE*((float)( base -MAX_OSC/2)/MAX_OSC); } SAMPLE MIDI2freq(int MIDI_note) { return 440 * pow(2,(((SAMPLE)MIDI_note-69)/12)); } int freq2MIDI(SAMPLE freq) { return (int)( 69 + 12*log(freq/440)/log((SAMPLE)2) ); } //this function calculates the positive modulus of a number int MyModulo( int num, int mod ) { int result = num % mod; if( result < 0 ) return (result + mod); else return result; } //this function calculates which array you would end up in if you go to index j //if j is outside of the current array's bounds it goes to the next or previous //array respectively. returns the array index into int GetRelativeArray( int index, int currentArray, int sizeArray, int numArrays ) { double arrayChange = floor( (double)index / (double)sizeArray ); int returnArray = MyModulo( currentArray + arrayChange, numArrays ); return returnArray; } void GraphicsProcessing( SAMPLE * buffy, int buffer_size ) { //setup a second buffer so that we can visualize both the windowed signal and the FFT signal SAMPLE * buffer_windowed = new SAMPLE[buffer_size]; //create the history buffer to display the input over longer time periods for( int i = 0; i < buffer_size; i++ ) g_signalHistory[g_curPosHistory][i] = buffy[i]; /* //The FFT //------------------------------ //create the window SAMPLE * window = new SAMPLE[buffer_size]; SAMPLE * FFT = new SAMPLE[2*buffer_size]; //make array for FFT return for( int i = 0; i < 2*buffer_size; i++ ) FFT[i] = 0; //zero out FFT array for zero padding complex * cFFT; /* if (theData->window == W_RECT) { for(int i = 0; i < buffer_size; i++) window[i] = 1; } hamming(window, buffer_size); hanning(window, buffer_size); blackman(window, buffer_size); */ //hardcoded window for now /* blackman(window, buffer_size); //apply the window to the signal for( int i = 0; i < buffer_size; i++ ) buffer_windowed[i] = buffy[i]; apply_window(buffer_windowed, window, buffer_size); //the FFT for(int i=0; i> errorwait; cerr << "baaaaaaaaad..." << endl; return 1; } RtAudio dac; // Figure out how many bytes in an StkFloat and setup the RtAudio stream. RtAudio::StreamParameters parameters; parameters.deviceId = dac.getDefaultOutputDevice(); parameters.nChannels = 1; RtAudio::StreamParameters parameters2; parameters2.deviceId = dac.getDefaultInputDevice(); parameters2.nChannels = 1; RtAudioFormat format = ( sizeof(StkFloat) == 8 ) ? RTAUDIO_FLOAT64 : RTAUDIO_FLOAT32; unsigned int bufferFrames = RT_BUFFER_SIZE; try { dac.openStream( ¶meters, ¶meters2, format, (unsigned int)Stk::sampleRate(), &bufferFrames, &tick, NULL ); } catch ( RtError &error ) { error.printMessage(); string errorwait; cin >> errorwait; goto cleanup; } try { dac.startStream(); } catch ( RtError &error ) { error.printMessage(); goto cleanup; } // let GLUT handle the current thread from here glutMainLoop(); /* // Block waiting here. char keyhit; std::cout << "\nPlaying ... press to quit.\n"; std::cin.get( keyhit ); */ // Shut down the output stream. try { dac.closeStream(); } catch ( RtError &error ) { error.printMessage(); } cleanup: return 0; } //----------------------------------------------------------------------------- // Name: reshapeFunc( ) // Desc: called when window size changes //----------------------------------------------------------------------------- void reshapeFunc( GLsizei w, GLsizei h ) { // save the new window size g_width = w; g_height = h; // map the view port to the client area glViewport( 0, 0, w, h ); // set the matrix mode to project glMatrixMode( GL_PROJECTION ); // load the identity matrix glLoadIdentity( ); // create the viewing frustum gluPerspective( 45.0, (GLfloat) w / (GLfloat) h, 1.0, 300.0 ); // set the matrix mode to modelview glMatrixMode( GL_MODELVIEW ); // load the identity matrix glLoadIdentity( ); // position the view point gluLookAt( 0.0f, 0.0f, 10.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f ); //gluLookAt( 0.0f, 1.75f, 5.0f, 0.0f, 1.75f, 4.0f, 0.0f, 1.0f, 0.0f ); } //----------------------------------------------------------------------------- // Name: keyboardFunc( ) // Desc: key event //----------------------------------------------------------------------------- void keyboardFunc( unsigned char key, int x, int y ) { switch( key ) { case '1': if( g_biquad_avatar._on == true ) g_biquad_avatar._on = false; else g_biquad_avatar._on = true; break; case '9': g_userInteractors = 1; break; case '0': g_userInteractors = 0; break; case 'p': g_print = 1; break; case 'Q': case 'q': exit(1); break; } glutPostRedisplay( ); } //----------------------------------------------------------------------------- // Name: mouseFunc( ) // Desc: handles mouse stuff //----------------------------------------------------------------------------- void mouseFunc( int button, int state, int x, int y ) { if( button == GLUT_LEFT_BUTTON ) { // when left mouse button is down if( state == GLUT_DOWN ) { } else { } } else if ( button == GLUT_RIGHT_BUTTON ) { // when right mouse button down if( state == GLUT_DOWN ) { } else { } } else { } glutPostRedisplay( ); } //----------------------------------------------------------------------------- // Name: idleFunc( ) // Desc: callback from GLUT //----------------------------------------------------------------------------- void idleFunc( ) { // render the scene glutPostRedisplay( ); } //------------------------------ // (jesse) // FUNCTION for rendering strings to the screen //from http://www.lighthouse3d.com/opengl/glut/index.php?bmpfont //------------------------------- void renderBitmapString( float x, float y, float z, void *font, char *string) { char *c; glRasterPos3f(x, y,z); for (c=string; *c != '\0'; c++) { glutBitmapCharacter(font, *c); } } void renderSpacedBitmapString( float x, float y, int spacing, void *font, char *string) { char *c; int x1=x; for (c=string; *c != '\0'; c++) { glRasterPos2f(x1,y); glutBitmapCharacter(font, *c); x1 = x1 + glutBitmapWidth(font,*c) + spacing; } } void setOrthographicProjection() { // switch to projection mode glMatrixMode(GL_PROJECTION); // save previous matrix which contains the //settings for the perspective projection glPushMatrix(); // reset matrix glLoadIdentity(); // set a 2D orthographic projection gluOrtho2D(0, g_width, 0, g_height); // invert the y axis, down is positive glScalef(1, -1, 1); // mover the origin from the bottom left corner // to the upper left corner glTranslatef(0, -g_height, 0); glMatrixMode(GL_MODELVIEW); } void resetPerspectiveProjection() { glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); } //----------------------------------------------------------------------------- // Name: displayFunc( ) // Desc: callback function invoked to draw the client area //----------------------------------------------------------------------------- void displayFunc( ) { //print text to the screen setOrthographicProjection(); glPushMatrix(); glLoadIdentity(); renderBitmapString(5,30,0, GLUT_BITMAP_HELVETICA_18,"3D Tech"); glPopMatrix(); resetPerspectiveProjection(); /* glPushMatrix(); glRasterPos2f(-3, 0); glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18, 'C'); glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18, 'C'); glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18, 'C'); glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18, 'C'); glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18, 'C'); glPopMatrix(); */ /* cout << glutStrokeWidth(GLUT_STROKE_ROMAN, 'R'); for(int i = 0; i < 100; i++) { glPushMatrix(); glTranslatef(0,0,0); glutStrokeCharacter(GLUT_STROKE_ROMAN,'3'); glPopMatrix(); }*/ glPushMatrix(); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glColor3f(0.9f, 0.9f, 0.9f); glBegin(GL_QUADS); glVertex3f(-100.0f, 0.0f, -100.0f); glVertex3f(-100.0f, 0.0f, 100.0f); glVertex3f( 100.0f, 0.0f, 100.0f); glVertex3f( 100.0f, 0.0f, -100.0f); glEnd(); glPopMatrix(); if( g_userInteractors == 1 ) { // local state static GLfloat zrot = 0.0f, c = 0.0f, XZrot = 0.0f, YZrot = 0.0f; // clear the color and depth buffers glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); // line width glLineWidth( 2.0 ); // step through and plot the waveform GLfloat y = -2.5; GLfloat z = -2.5; // increment GLfloat yinc = ::fabs(2*y / (g_bufferSize)); GLfloat zinc = ::fabs(2*z / (g_bufferSize)); // push the matrix glPushMatrix(); //plotting the waterfall: frequency signal with time in the z axis for( int j = 0; j < NUM_WATERFALLS; j++) { int FFT_index = (curPosFFT + j) % NUM_WATERFALLS; //center the plot of the waveform GLfloat x = -5; //increment the right amount to center the waveform GLfloat xinc = ::fabs(2*x / (g_bufferSize)); // go glBegin( GL_LINE_STRIP ); // loop through global buffer for( int i = 0; i < g_bufferSize; i++ ) { // set the color glColor3f( (sin(c)+1)/2, (sin(c*2)+1)/2, (sin(c+.5)+1)/2 ); // set the next vertex //different ways we can scale the visual //glVertex3f( x, (20.0f * log10( g_buffer_FFT[FFT_index][i]/8.0 ) + 80.0f)/80.0f - 3, -8 + (SAMPLE)j/2); // glVertex3f( x, 1.5f*pow( 25 * g_buffer_FFT[FFT_index][i], 0.5f ) - 3, -8 + (SAMPLE)j/2); //glVertex3f( x, 10*fabs(g_buffer_FFT[FFT_index][i]) - 3, -8 +((SAMPLE)j)/2); //glVertex2f( x, 5*g_buffer_FFT[i] - 4 ); // increment x x += xinc; } // done glEnd(); } /* //plotting the windowed signal of length buffer_size // go glBegin( GL_LINE_STRIP ); for( int j = 0; j < g_bufferSize; j++) { //set the color glColor3f( (sin(c)+1)/2, (sin(c*2)+1)/2, (sin(c+.5)+1)/2 ); //set the next vertex glVertex2f( y - 2.5, 2*g_buffer_windowed[j] + 3 ); //increment y y += yinc; } // done glEnd();*/ //plotting the longer history of the signal GLfloat w = -5; GLfloat winc = ::fabs(2*w / (g_bufferSize * SIZE_HISTORY)); //trying to plot in a circle in XZ plane //diameter of circle //float diameter = (float)(g_bufferSize*SIZE_HISTORY)/(2*MY_PIE); // go for( int j = 0; j < SIZE_HISTORY; j++) { int history_index = (g_curPosHistory + j) % SIZE_HISTORY; glBegin( GL_LINE_STRIP ); for( int j = 0; j < g_bufferSize; j++) { //set the color glColor3f( (sin(c)+1)/2, (sin(c*2)+1)/2, (sin(c+.5)+1)/2 ); //set the next vertex glVertex2f( w, 2 * g_signalHistory[history_index][j] - 1.5 ); //increment w w += winc; } } // done glEnd(); //plotting the longer history of the signal // go w = -5; for( int j = 0; j < SIZE_HISTORY; j++) { int history_index = (g_curPosHistory + j) % SIZE_HISTORY; glBegin( GL_LINE_STRIP ); for( int j = 0; j < g_bufferSize; j++) { //set the color based on the power if(g_powerHistory[history_index][j] < POWER_THRESHOLD_MIN) //this sets the cutoff for noise glColor3f( 0, 0, 1 ); else if( g_powerHistory[history_index][j] < POWER_THRESHOLD_MAX ) glColor3f( 0, 1, 0 ); else glColor3f( 1, 0, 0 ); //set the next vertex glVertex2f( w, 2 * g_powerHistory[history_index][j] + 1 ); //increment w w += winc; } } // done glEnd(); //create a sphere for each user with iterator map::iterator iter; for( iter = g_audience.begin(); iter != g_audience.end(); iter++ ) { //user controled sphere float radiusMod = RADIUS_MOD; for( int i = 0; i < SPHERE_HISTORY; i+=(SPHERE_HISTORY/NUM_SPHERE)) { int iCurPosIndexX = MyModulo( iter->second.sphereCurrX - i, SPHERE_HISTORY ); int iCurPosIndexY = MyModulo( iter->second.sphereCurrY - i, SPHERE_HISTORY ); glPushMatrix(); glColor3f( (sin( (iter->second).sphereColor)+1)/2, (sin( (iter->second).sphereColor*2)+1)/2, (sin((iter->second).sphereColor+.5)+1)/2 ); glTranslatef( (iter->second).sphereX[iCurPosIndexX], (iter->second).sphereY[iCurPosIndexY], 0.0f ); // rotation glRotatef( zrot, 0, 0, 1 ); zrot += (iter->second).rotValXY; glRotatef( XZrot, 0, 1, 0 ); XZrot += (iter->second).rotValXZ; glRotatef( YZrot, 1, 0, 0 ); YZrot += (iter->second).rotValYZ; glutWireTorus( SPHERE_RADIUS*radiusMod/4, SPHERE_RADIUS*radiusMod/2, 20, 20); //glutWireCube( SPHERE_RADIUS*radiusMod); //glutWireSphere( SPHERE_RADIUS*radiusMod, 20, 20 ); radiusMod *= radiusMod; glPopMatrix(); } } if( g_biquad_avatar._on == true ) { //create sphere were biquad filter is in parameter space glPushMatrix(); int counterA = 0; float xcoord = 0; float ycoord = 0; //slight color shift float colorOne = 1; float colorTwo = 1; float colorThree = 1; for( iter = g_audience.begin(); iter != g_audience.end(); iter++ ) { if( iter->second.filterCtrl == 1 ) { colorOne += .5 * (sin((iter->second).sphereColor)+1)/2; colorTwo += .5 * (sin((iter->second).sphereColor*2)+1)/2; colorThree += .5 * (sin((iter->second).sphereColor+.5)+1)/2; xcoord += iter->second.biquad_width; ycoord += iter->second.biquad_freq; counterA++; } } if(counterA != 0 ) { colorOne = colorOne/(float)counterA; colorTwo = colorTwo/(float)counterA; colorThree = colorThree/(float)counterA; cout << colorOne << " "; xcoord = xcoord/(float)counterA; ycoord = ycoord/(float)counterA; //give physics feel to movement: g_biquad_avatar.coordx += .2 * ( xcoord - g_biquad_avatar.coordx ); g_biquad_avatar.coordy += .2 * ( ycoord - g_biquad_avatar.coordy ); } glPushMatrix(); glBegin(GL_LINES); for( iter = g_audience.begin(); iter != g_audience.end(); iter++ ) { if( iter->second.filterCtrl == 1 ) { glColor3f( colorOne, colorTwo, colorThree); glVertex2f(iter->second.sphereX[iter->second.sphereCurrX], iter->second.sphereY[iter->second.sphereCurrY]); glVertex2f(BaseCoordX(g_biquad_avatar.coordx), BaseCoordY(g_biquad_avatar.coordy)); } } glEnd(); glPopMatrix(); glColor3f( 1, 1, 1 ); glTranslatef( BaseCoordX(g_biquad_avatar.coordx), BaseCoordY(g_biquad_avatar.coordy), 0.0f ); int history_index = (g_curPosHistory) % SIZE_HISTORY; float radiusTemp = .25 * SPHERE_RADIUS + log( 1 + 10*g_powerHistory[history_index][0] )/log(10.0f); glutSolidTorus( radiusTemp/2, radiusTemp, 20, 20 ); glPopMatrix(); // increment color c += .001; // pop glPopMatrix(); } } // flush! glFlush( ); // swap the double buffer glutSwapBuffers( ); }