//------------------------------------------------------------------------------
// BORDERLANDS:  An interactive granular sampler.  
//------------------------------------------------------------------------------
// More information is available at 
//     http::/ccrma.stanford.edu/~carlsonc/256a/Borderlands/index.html
//
//
// Copyright (C) 2011  Christopher Carlson
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 3.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see &lt;http://www.gnu.org/licenses/&gt;.


//
//  main.cpp
//  Borderlands
//
//  Created by Christopher Carlson on 11/13/11.
//


//my includes
#include &quot;theglobals.h&quot;

//graphics includes
#ifdef __MACOSX_CORE__
#include &lt;GLUT/glut.h&gt;
#else
#include &lt;GL/gl.h&gt;
#include &lt;GL/glu.h&gt;
#include &lt;GL/glut.h&gt;
#endif

//other libraries
#include &lt;iostream&gt;
#include &lt;sys/stat.h&gt;
#include &lt;vector&gt;
#include &lt;string.h&gt;
#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;cstdio&gt;
#include &lt;cstdlib&gt;
#include &lt;sstream&gt;
#include &lt;dirent.h&gt;

//audio related
#include &quot;MyRtAudio.h&quot;
#include &quot;AudioFileSet.h&quot;
#include &quot;Window.h&quot;

//graphics related
#include &quot;SoundRect.h&quot;

//graphics and audio related
#include &quot;GrainCluster.h&quot;

#ifndef WIN32
    #include &lt;sys/types.h&gt;
#endif


using namespace std;

unsigned int screenWidth, screenHeight;


//-----------------------------------------------------------------------------
// Defines a point in a 3D space (coords x, y and z)
//-----------------------------------------------------------------------------
struct pt3d
{ 
    pt3d( GLfloat _x, GLfloat _y, GLfloat _z ) : x(_x), y(_y), z(_z) {};
    
    float x;
    float y;
    float z;
};



//-----------------------------------------------------------------------------
// Shared Data Structures, Global parameters
//-----------------------------------------------------------------------------
//audio system
MyRtAudio * theAudio = NULL;
//library path
//string g_audioPath = &quot;/usr/share/Borderlands/loops/&quot;;
string g_audioPath = &quot;&quot;;
string g_repUser = getenv(&quot;HOME&quot;);
string g_programPathUser = g_repUser + &quot;/.Borderlands/&quot;;
string g_audioPathUser = g_repUser + &quot;/.Borderlands/loops/&quot;;
string g_audioPathDefault = &quot;/usr/share/Borderlands/loops/&quot;;
//parameter string
string paramString = &quot;&quot;;
//desired audio buffer size 
unsigned int g_buffSize = 1024;
//audio files
vector &lt;AudioFile *&gt; * mySounds = NULL;
//audio file visualization objects
vector &lt;SoundRect *&gt; * soundViews = NULL;
//grain cloud audio objects
vector&lt;GrainCluster *&gt; * grainCloud = NULL;
//grain cloud visualization objects
vector&lt;GrainClusterVis *&gt; * grainCloudVis;
//cloud counter
unsigned int numClouds = 0;

//global time increment - samples per second
//global time is incremented in audio callback
const double samp_time_sec = (double) 1.0 / (double)MY_SRATE;


//Initial camera movement vars
//my position
pt3d position(0.0,0.0,0.0f);


//ENUMS 
//user selection mode
enum{RECT,CLOUD};
enum{MOVE,RESIZE};
//default selection mode
int selectionMode = CLOUD;
int dragMode = MOVE;
bool resizeDir = false; //for rects
//rubber band select params
int rb_anchor_x = -1;
int rb_anchor_y = -1;

//not used yet - for multiple selection
vector&lt;int&gt; * selectionIndices = new vector&lt;int&gt;;

//selection helper vars
int selectedCloud = -1;
int selectedRect = -1;
bool menuFlag = true;
int selectionIndex = 0;

//cloud parameter changing
enum{NUMGRAINS,DURATION,WINDOW, MOTIONX, MOTIONY,MOTIONXY,DIRECTION,OVERLAP, PITCH, ANIMATE,P_LFO_FREQ,P_LFO_AMT,SPATIALIZE,VOLUME};
//flag indicating parameter change
bool paramChanged = false;
unsigned int currentParam = NUMGRAINS;
double lastParamChangeTime = 0.0;
double tempParamVal = -1.0;




//mouse coordinate initialization
int mouseX = -1;
int mouseY = -1;
long veryHighNumber = 50000000;
long lastDragX = veryHighNumber;
long lastDragY = veryHighNumber;


//--------------------------------------------------------------------------------
// FUNCTION PROTOTYPES
//--------------------------------------------------------------------------------

void idleFunc();
void displayFunc();
void reshape(int w, int h);
void specialFunc(int key, int x, int y);
void keyboardFunc(unsigned char key, int x, int y);
void keyUpFunc(unsigned char key, int x, int y);
void deselect(int mode);

void mouseFunc(int button, int state, int x, int y);
void mouseDrag(int x, int y);
void mousePassiveMotion(int x, int y);
void updateMouseCoords(int x, int y);
void initialize();
void draw_string( GLfloat x, GLfloat y, GLfloat z, const char * str, GLfloat scale);
void printUsage();
void printParam();
void drawAxis();
int audioCallback( void * outputBuffer, void * inputBuffer, unsigned int numFrames, double streamTime,RtAudioStreamStatus status, void * userData);
void cleaningFunction();




//--------------------------------------------------------------------------------
// Cleanup code
//--------------------------------------------------------------------------------

void cleaningFunction(){
    try {
        theAudio-&gt;stopStream();
        theAudio-&gt;closeStream();
    } catch (RtError &amp;err) {
        err.printMessage();
    }
    if (mySounds != NULL)
        delete mySounds;
    if (theAudio !=NULL)
        delete theAudio;
    
    if (grainCloud!=NULL){
        delete grainCloud;
    }    
    
    if (grainCloudVis!=NULL){
        delete grainCloudVis;
    }
    if (soundViews != NULL){
        delete soundViews;
    }
    if (selectionIndices != NULL){
        delete selectionIndices;
    }
}




//================================================================================
//   Audio Callback
//================================================================================

//audio callback
int audioCallback( void * outputBuffer, void * inputBuffer, unsigned int numFrames, double streamTime,
                  RtAudioStreamStatus status, void * userData)
{
        //cast audio buffers
    SAMPLE * out = (SAMPLE *)outputBuffer;
    SAMPLE * in = (SAMPLE *)inputBuffer;
    
    memset(out, 0, sizeof(SAMPLE)*numFrames*MY_CHANNELS );
    if (menuFlag == false){
        for(int i = 0; i &lt; grainCloud-&gt;size(); i++){
            grainCloud-&gt;at(i)-&gt;nextBuffer(out, numFrames);
        }
    }
    GTime::instance().sec += numFrames*samp_time_sec;
    // cout &lt;&lt; GTime::instance().sec&lt;&lt;endl;
    return 0;
}




//================================================================================
//   GRAPHICS/GLUT
//================================================================================

void windowInit(){    
    // assign glut function calls
    glutIdleFunc(idleFunc);
    glutReshapeFunc(reshape);
    glutDisplayFunc(displayFunc);
    glutMouseFunc(mouseFunc);
    glutMotionFunc(mouseDrag);
    glutPassiveMotionFunc(mousePassiveMotion);
    glutKeyboardFunc(keyboardFunc);
    glutKeyboardUpFunc(keyUpFunc);
    // set the special function - called on special keys events (fn, arrows, pgDown, etc)
    glutSpecialFunc( specialFunc );
}


void toggleFullScreen(){
    static bool isFullScreen = true;


    if (isFullScreen)
    {

        glutReshapeWindow(0.6*screenWidth,0.6*screenHeight);
        glutPositionWindow(screenWidth*0.1,100);
        isFullScreen = false;
        /*
        glutLeaveGameMode();
        cout &lt;&lt; &quot;left game mode&quot; &lt;&lt; endl;
        windowInit();
        glutMainLoop();
        */
        
        
    }else{
        
        /*
        //glutFullScreen();
        string res;
        char buffer[33];
        screenWidth = glutGet(GLUT_SCREEN_WIDTH);
        sprintf(buffer, &quot;%d&quot;, screenWidth);
        res.append(buffer);
        res.append(&quot;x&quot;);
        char buffer2[33];
        screenHeight = glutGet(GLUT_SCREEN_HEIGHT);
        sprintf(buffer2,&quot;%d&quot;,screenHeight);
        res.append(buffer2);
        res.append(&quot;:32@75&quot;);
        cout &lt;&lt; res.c_str() &lt;&lt; endl;
        
        //presentation view
        //set resolution/refresh rate
        glutGameModeString(res.c_str());
        glutEnterGameMode();
        cout &lt;&lt; &quot;entered game mode&quot; &lt;&lt; endl;

                windowInit();
        glutMainLoop();
        */
        glutFullScreen();
        
        isFullScreen = true;
    }
    
    //glutDisplayFunc(displayFunc);

}


//-----------------------------------------------------------
//  GLUT Initialization
//-----------------------------------------------------------

void initialize()
{
    
    
    // initial window settings
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH );
    
    
    screenWidth = glutGet(GLUT_SCREEN_WIDTH);
    screenHeight = glutGet(GLUT_SCREEN_HEIGHT);
    glutInitWindowSize (screenWidth,screenHeight);
    glutInitWindowPosition (0, 0);
    glutCreateWindow(&quot;Borderlands&quot;);
    

    /*
    //Game Mode   
    string res;
    char buffer[33];
    screenWidth = glutGet(GLUT_SCREEN_WIDTH);
    sprintf(buffer, &quot;%d&quot;, screenWidth);
    res.append(buffer);
    res.append(&quot;x&quot;);
    char buffer2[33];
    screenHeight = glutGet(GLUT_SCREEN_HEIGHT);
    sprintf(buffer2,&quot;%d&quot;,screenHeight);
    res.append(buffer2);
    res.append(&quot;:32@75&quot;);
    cout &lt;&lt; res.c_str() &lt;&lt; endl;
    
    //presentation view
    //set resolution/refresh rate
    glutGameModeString(res.c_str());
    glutEnterGameMode();
    
    */
        
    //full screen end
    
    // initial state
    glClearColor(0.15, 0.15, 0.15,1.0f);
    //enable depth buffer updates
    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LEQUAL);
    //set polys with counterclockwise winding to be front facing 
    //this is gl default anyway
    glFrontFace( GL_CCW );
    //set fill mode
    glPolygonMode( GL_FRONT_AND_BACK, GL_FILL);
    glPolygonMode( GL_FRONT_AND_BACK, GL_POLYGON_SMOOTH);
    //enable transparency
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    //antialias lines and points
    glEnable(GL_LINE_SMOOTH);
    glEnable(GL_POINT_SMOOTH);
    glHint(GL_LINE_SMOOTH_HINT,GL_NICEST);
    glHint(GL_POINT_SMOOTH_HINT,GL_NICEST);
    glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
    glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
    glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);
    
    // assign glut function calls
    glutIdleFunc(idleFunc);
    glutReshapeFunc(reshape);
    glutDisplayFunc(displayFunc);
    glutMouseFunc(mouseFunc);
    glutMotionFunc(mouseDrag);
    glutPassiveMotionFunc(mousePassiveMotion);
    glutKeyboardFunc(keyboardFunc);
    glutKeyboardUpFunc(keyUpFunc);
    // set the special function - called on special keys events (fn, arrows, pgDown, etc)
    glutSpecialFunc( specialFunc );
    
    glutFullScreen();
    


}



//------------------------------------------------------------------------------
// GLUT display function
//------------------------------------------------------------------------------
void displayFunc()
{
    //clear color and depth buffers
    glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
    glClearDepth(1.0);
    
    ////PUSH //save current transform
    glPushMatrix();
    
    glLoadIdentity();
    
    //update viewer position
    glTranslatef(-position.x,-position.y,-position.z); //translate the screen to the position of our camera
    if (menuFlag == false){
        //render rectangles
        if (soundViews){
            for (int i = 0; i &lt; soundViews-&gt;size(); i++)
            {
                soundViews-&gt;at(i)-&gt;draw();
            }
        }
        
         //render grain clouds if they exist
         if (grainCloudVis){
             for (int i = 0; i &lt; grainCloudVis-&gt;size(); i++)
             {
                 grainCloudVis-&gt;at(i)-&gt;draw();
             }
         }
        
//print current param if editing
        if ( (selectedCloud &gt;= 0) || (selectedRect &gt;= 0) )
            printParam();
    }else{
        printUsage();
    }
    
    
    
    //printUsage();
    
    //POP ---//restore state
    glPopMatrix();
    
    //flush and swap
    glFlush();//renders and empties buffers
    glutSwapBuffers(); // brings hidden buffer to the front (using double buffering for smoother graphics)
    
}




//------------------------------------------------------------------------------
// GLUT reshape function
//------------------------------------------------------------------------------
void reshape(int w, int h)
{
    glViewport(0, 0, (GLsizei) w, (GLsizei) h);
    screenWidth = w;
    screenHeight = h;
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(0.0, (GLdouble) screenWidth, 0.0, (GLdouble)screenHeight, -10.0, 10.0);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    glTranslatef(-position.x,-position.y,-position.z); //translate the screen to the position of our camera
    //request redisplay
    glutPostRedisplay( );
}


//-----------------------------------------------------------------------------
// GlUT idle function 
//-----------------------------------------------------------------------------

void idleFunc(){
    // render the scene
    glutPostRedisplay( );
}


///-----------------------------------------------------------------------------
// name: drawAxis()
// desc: draw 3d axis
//-----------------------------------------------------------------------------
void drawAxis()
{
    //PUSH -- //store state
    glPushMatrix();
    
    //specify vertices with this drawing mode
    glBegin(GL_LINES);
    glLineWidth(0.9f);
    //x axis
    glColor4f(1,0,0,0.9);
    glVertex3f(0,0,0);
    glVertex3f(screenWidth,0,0);
    
    //x axis
    glColor4f(0,1,0,0.9);
    glVertex3f(0,0,0);
    glVertex3f(0,screenHeight,0);
    
    //z axis
    glColor4f(0,0,1,0.7);
    glVertex3f(0,0,0);
    glVertex3f(0,0,400);
    
    //stop drawing
    glEnd();
    
    //POP -- //restore state
    glPopMatrix();
}


//-----------------------------------------------------------------------------
// Display simple string
// desc: from sndpeek source - Ge Wang, et al
//-----------------------------------------------------------------------------
void draw_string( GLfloat x, GLfloat y, GLfloat z, const char * str, GLfloat scale = 1.0f )
{
    GLint len = strlen( str ), i;
    
    glPushMatrix();
    glTranslatef( x, screenHeight-y, z );
    glScalef( .001f * scale, .001f * scale, .001f * scale );
    
    for( i = 0; i &lt; len; i++ )
        glutStrokeCharacter( GLUT_STROKE_MONO_ROMAN, str[i] );
    
    glPopMatrix();
}


//-----------------------------------------------------------------------------
// Show usage on screen.  TODO:  add usage info 
//-----------------------------------------------------------------------------
void printUsage(){
    float smallSize = 0.03f;
    float mediumSize = 0.04f;
    glLineWidth(2.0f);
    float theA = 0.6f + 0.2*sin(0.8*PI*GTime::instance().sec);
    glColor4f(theA,theA,theA,theA);
    draw_string(screenWidth/2.0f + 0.2f*(float)screenWidth,(float)screenHeight/2.0f, 0.5f,&quot;BORDERLANDS&quot;,(float)screenWidth*0.1f);
   
    theA = 0.6f + 0.2*sin(0.9*PI*GTime::instance().sec);
    float insColor = theA*0.4f;
    glColor4f(insColor,insColor,insColor,theA);
    //key info
    draw_string(screenWidth/2.0f + 0.2f*(float)screenWidth + 10.0,(float)screenHeight/2.0f + 30.0, 0.5f,&quot;CLIC POUR DEMARRER&quot;,(float)screenWidth*0.04f);

    theA = 0.6f + 0.2*sin(1.0*PI*GTime::instance().sec);
    insColor = theA*0.4f;
    glColor4f(insColor,insColor,insColor,theA);
    //key info
    draw_string(screenWidth/2.0f + 0.2f*(float)screenWidth+10.0,(float)screenHeight/2.0f + 50.0, 0.5f,&quot;ECHAP POUR QUITTER&quot;,(float)screenWidth*0.04f);

    //key info
    draw_string(screenWidth/2.0f + 0.2f*(float)screenWidth+10.0,(float)screenHeight/2.0f + 70.0, 0.5f,&quot;METTRE LES ECHANTILLONS DANS .Borderlands/loops&quot;,(float)screenWidth*0.04f);
    
}


void printParam(){
    if ((numClouds &gt; 0) &amp;&amp; (selectedCloud &gt;=0)){
        GrainClusterVis * theCloudVis= grainCloudVis-&gt;at(selectedCloud);
        GrainCluster * theCloud = grainCloud-&gt;at(selectedCloud);
        float cloudX = theCloudVis-&gt;getX();
        float cloudY = theCloudVis-&gt;getY();
        string myValue;
        ostringstream sinput;
        ostringstream sinput2;
        float theA = 0.7f + 0.3*sin(1.6*PI*GTime::instance().sec);
        glColor4f(1.0f,1.0f,1.0f,theA);
        
        switch (currentParam) {
            case NUMGRAINS:
                myValue = &quot;Voix : &quot;;
                sinput &lt;&lt; theCloud-&gt;getNumVoices();            
                myValue = myValue+ sinput.str();
                draw_string((GLfloat)mouseX,(GLfloat) (screenHeight-mouseY),0.0,myValue.c_str(),100.0f);
                break;
            case DURATION:
                myValue = &quot;Duree : &quot;;
                if (paramString == &quot;&quot;){
                    sinput &lt;&lt; theCloud-&gt;getDurationMs();
                    myValue = myValue + sinput.str() + &quot; ms&quot;;
                }else{
                    myValue = myValue + paramString + &quot; ms&quot;;
                }
                draw_string((GLfloat)mouseX,(GLfloat) (screenHeight-mouseY),0.0,myValue.c_str(),100.0f);
                //            myValue = &quot;Duration (ms): &quot; + theCloud-&gt;getDurationMs();
                break;
            case WINDOW:
                switch (theCloud-&gt;getWindowType()) {
                    case HANNING:
                        myValue = &quot;Enveloppe : HANNING&quot;;
                        break;
                    case TRIANGLE:
                        myValue = &quot;Enveloppe : TRIANGLE&quot;;
                        break;
                    case REXPDEC:
                        myValue = &quot;Enveloppe : REXPDEC&quot;;
                        break;
                    case EXPDEC:
                        myValue = &quot;Enveloppe : EXPDEC&quot;;
                        break;
                    case SINC:
                        myValue = &quot;Enveloppe : SINC&quot;;
                        break;
                    case RANDOM_WIN:
                        myValue = &quot;Enveloppe : RANDOM_WIN&quot;;
                        break;
                    default:
                        myValue = &quot;&quot;;
                        break;
                }
                
                draw_string((GLfloat)mouseX,(GLfloat) (screenHeight-mouseY),0.0,myValue.c_str(),100.0f);
                break;
            case MOTIONX:
                myValue = &quot;X : &quot;;
                sinput &lt;&lt; theCloudVis-&gt;getXRandExtent();
                myValue = myValue + sinput.str();
                draw_string((GLfloat)mouseX,(GLfloat) (screenHeight-mouseY),0.0,myValue.c_str(),100.0f);
                break;
            case MOTIONY:
                myValue = &quot;Y : &quot;;
                sinput &lt;&lt; theCloudVis-&gt;getYRandExtent();
                myValue = myValue + sinput.str();
                draw_string((GLfloat)mouseX,(GLfloat) (screenHeight-mouseY),0.0,myValue.c_str(),100.0f);
                break;
            case MOTIONXY:
                myValue = &quot;X,Y : &quot;;
                sinput &lt;&lt; theCloudVis-&gt;getXRandExtent();
                myValue = myValue + sinput.str() + &quot;, &quot;;
                sinput2 &lt;&lt; theCloudVis-&gt;getYRandExtent();
                myValue = myValue + sinput2.str();
                draw_string((GLfloat)mouseX,(GLfloat) (screenHeight-mouseY),0.0,myValue.c_str(),100.0f);
                break;
                
            case DIRECTION:
                switch(theCloud-&gt;getDirection()){
                    case FORWARD:
                        myValue = &quot;Direction : EN AVANT&quot;;
                        break;
                    case BACKWARD:
                        myValue = &quot;Direction : EN ARRIERE&quot;;
                        break;
                    case RANDOM_DIR:
                        myValue = &quot;Direction : HASARD&quot;;
                        break;
                    default:
                        myValue = &quot;&quot;;
                        break;
                }
                draw_string((GLfloat)mouseX,(GLfloat) (screenHeight-mouseY),0.0,myValue.c_str(),100.0f);  
                break;
                
            case SPATIALIZE:
                switch(theCloud-&gt;getSpatialMode()){
                    case UNITY:
                        myValue = &quot;Balance panoramique : UNITE&quot;;
                        break;
                    case STEREO:
                        myValue = &quot;Balance panoramique : STEREO&quot;;
                        break;
                    case AROUND:
                        myValue = &quot;Balance panoramique : AUTOUR&quot;;
                        break;
                    default:
                        myValue = &quot;&quot;;
                        break;
                }
                draw_string((GLfloat)mouseX,(GLfloat) (screenHeight-mouseY),0.0,myValue.c_str(),100.0f);  
                break;
            case VOLUME:
                myValue = &quot;Volume (dB) : &quot;;
                if (paramString == &quot;&quot;){
                    sinput &lt;&lt; theCloud-&gt;getVolumeDb();
                    myValue = myValue + sinput.str();
                }else{
                    myValue = myValue + paramString;
                }
                draw_string((GLfloat)mouseX,(GLfloat) (screenHeight-mouseY),0.0,myValue.c_str(),100.0f);
                break;
            case OVERLAP:
                myValue = &quot;Chevauchement : &quot;;
                if (paramString == &quot;&quot;){
                    sinput &lt;&lt; theCloud-&gt;getOverlap();
                    myValue = myValue + sinput.str();
                }else{
                    myValue = myValue + paramString;
                }
                draw_string((GLfloat)mouseX,(GLfloat) (screenHeight-mouseY),0.0,myValue.c_str(),100.0f);
                //            myValue = &quot;Duration (ms): &quot; + theCloud-&gt;getDurationMs();
                break;
            case PITCH:
                myValue = &quot;Tonalite : &quot;;
                if (paramString == &quot;&quot;){
                    sinput &lt;&lt; theCloud-&gt;getPitch();
                    myValue = myValue + sinput.str();
                }else{
                    myValue = myValue + paramString;
                }
                draw_string((GLfloat)mouseX,(GLfloat) (screenHeight-mouseY),0.0,myValue.c_str(),100.0f);
                //            myValue = &quot;Duration (ms): &quot; + theCloud-&gt;getDurationMs();
                break;
                
            case P_LFO_FREQ:
                myValue = &quot;Frequence LFO de la tonalite : &quot;;
                if (paramString == &quot;&quot;){
                    sinput &lt;&lt; theCloud-&gt;getPitchLFOFreq();
                    myValue = myValue + sinput.str();
                }else{
                    myValue = myValue + paramString;
                }
                draw_string((GLfloat)mouseX,(GLfloat) (screenHeight-mouseY),0.0,myValue.c_str(),100.0f);
                //            myValue = &quot;Duration (ms): &quot; + theCloud-&gt;getDurationMs();
                break;
            case P_LFO_AMT:
                myValue = &quot;Quantite LFO de la tonalite : &quot;;
                if (paramString == &quot;&quot;){
                    sinput &lt;&lt; theCloud-&gt;getPitchLFOAmount();
                    myValue = myValue + sinput.str();
                }else{
                    myValue = myValue + paramString;
                }
                draw_string((GLfloat)mouseX,(GLfloat) (screenHeight-mouseY),0.0,myValue.c_str(),100.0f);
                //            myValue = &quot;Duration (ms): &quot; + theCloud-&gt;getDurationMs();
                break;
            default:
                break;
        }
    }
    
}


//================================================================================
//   INTERACTION/GLUT
//================================================================================


//update mouse coords based on mousemovement
void updateMouseCoords(int x, int y){
    mouseX = x+position.x;
    mouseY = (screenHeight - (y-position.y) );
}


//-----------------------------------------------------------------------------
// Handle special function keys (arrows, etc)
//-----------------------------------------------------------------------------
void specialFunc( int key, int x, int y )
{
    static float sidewaysMoveSpeed = 10.0f;
    static float upDownMoveSpeed = 10.0f;
    //cout &lt;&lt; &quot;special key&quot; &lt;&lt; key &lt;&lt;endl;
    
    switch (key){
        case GLUT_KEY_LEFT:
            //move to the left
            position.x -=  sidewaysMoveSpeed;
            mouseX -=sidewaysMoveSpeed;
            break;
        case GLUT_KEY_RIGHT:
            //move to the right
            position.x += sidewaysMoveSpeed;
            mouseX +=sidewaysMoveSpeed;
            break;
        case GLUT_KEY_DOWN:
            //move backward
            position.y -= upDownMoveSpeed;
            mouseY +=sidewaysMoveSpeed;
            
            break;
        case GLUT_KEY_UP:
            //move forward
            position.y += upDownMoveSpeed;
            mouseY -=sidewaysMoveSpeed;
            break;
            
        case 14:
            //cout &lt;&lt; &quot;shift down&quot; &lt;&lt; endl;
            break;
        case 15://shift in
            //cout &lt;&lt; &quot;shift up&quot; &lt;&lt; endl;
            
            break;
            
        default:
            break;
    }
    //request redisplay
    glutPostRedisplay( );
}




//-----------------------------------------------------------------------------
// Handle key up events (other than special keys)
//-----------------------------------------------------------------------------

void keyUpFunc( unsigned char key, int x, int y ){
    //cout &lt;&lt; key &lt;&lt; endl;
    switch (key) {
        case &#039;a&#039;:
            break;
        case &#039;R&#039;:
        case &#039;r&#039;:
            dragMode = MOVE;
            lastDragX = veryHighNumber;
            lastDragY = veryHighNumber;
            break;
        default:
            break;
    }
    glutPostRedisplay( );
}


//-----------------------------------------------------------------------------
// Handle key down events (other than special keys)
//-----------------------------------------------------------------------------
void keyboardFunc( unsigned char key, int x, int y )
{
    static bool negativeFlag = false;//for negative value entry
    int modkey = glutGetModifiers();
    //cout &lt;&lt; &quot;key pressed &quot; &lt;&lt; key &lt;&lt; endl;
    switch( key )
    {
        
        case 9: //tab key
            
            if (selectionIndices-&gt;size() &gt; 1){
                soundViews-&gt;at(selectedRect)-&gt;setSelectState(false);
                selectionIndex++;
                if (selectionIndex &gt;= selectionIndices-&gt;size()){
                    selectionIndex = 0;
                }
                selectedRect = selectionIndices-&gt;at(selectionIndex);
                soundViews-&gt;at(selectedRect)-&gt;setSelectState(true);
            }
            break;
        case &#039;1&#039;:
            paramString.push_back(&#039;1&#039;);
            if (currentParam == WINDOW){
                    if (selectedCloud &gt;=0){
                        grainCloud-&gt;at(selectedCloud)-&gt;setWindowType(0);
                    }
            }

            break;
        case &#039;2&#039;:
            paramString.push_back(&#039;2&#039;);
            if (currentParam == WINDOW){
                if (selectedCloud &gt;=0){
                    grainCloud-&gt;at(selectedCloud)-&gt;setWindowType(1);
                }
            }
            break;
        case &#039;3&#039;:
            paramString.push_back(&#039;3&#039;);
            if (currentParam == WINDOW){
                if (selectedCloud &gt;=0){
                    grainCloud-&gt;at(selectedCloud)-&gt;setWindowType(2);
                }
            }
            break;
            
        case &#039;4&#039;:
            paramString.push_back(&#039;4&#039;);
            if (currentParam == WINDOW){
                if (selectedCloud &gt;=0){
                    grainCloud-&gt;at(selectedCloud)-&gt;setWindowType(3);
                }
            }
            break;
        case&#039;5&#039;:
            paramString.push_back(&#039;5&#039;);
            if (currentParam == WINDOW){
                if (selectedCloud &gt;=0){
                    grainCloud-&gt;at(selectedCloud)-&gt;setWindowType(4);
                }
            }
            break;
        case&#039;6&#039;:
            paramString.push_back(&#039;6&#039;);
            if (currentParam == WINDOW){
                if (selectedCloud &gt;=0){
                    grainCloud-&gt;at(selectedCloud)-&gt;setWindowType(5);
                }
            }
            break;
        case&#039;7&#039;:
            paramString.push_back(&#039;7&#039;);
            break;
        case&#039;8&#039;:
            paramString.push_back(&#039;8&#039;);
            break;
        case&#039;9&#039;:
            paramString.push_back(&#039;9&#039;);
            break;
        case &#039;0&#039;:
            paramString.push_back(&#039;0&#039;);
            break;
        case &#039;.&#039;:
            paramString.push_back(&#039;.&#039;);            
            break;
            
        case 13://enter key - for saving param string
            if (paramString != &quot;&quot;){
                float value = atof(paramString.c_str());
                
                //cout &lt;&lt; &quot;value received &quot; &lt;&lt; value &lt;&lt; endl;
                switch (currentParam){
                    case DURATION:
                        if (selectedCloud &gt;=0){
                            if (value &lt; 1.0){
                                value = 1.0;
                            }
                            grainCloud-&gt;at(selectedCloud)-&gt;setDurationMs(value);
                        }
                        break;
                    case OVERLAP:
                        if (selectedCloud &gt;=0){
                            grainCloud-&gt;at(selectedCloud)-&gt;setOverlap(value);
                        }
                        break;
                    case PITCH:
                        if (selectedCloud &gt;=0){
                            grainCloud-&gt;at(selectedCloud)-&gt;setPitch(value);
                        }
                        break;
                    case P_LFO_FREQ:
                        if (selectedCloud &gt;=0){
                            grainCloud-&gt;at(selectedCloud)-&gt;setPitchLFOFreq(value);
                        }
                        break;
                    case P_LFO_AMT:
                        if (selectedCloud &gt;=0){
                            grainCloud-&gt;at(selectedCloud)-&gt;setPitchLFOAmount(value);
                        }
                        break;
                        
                    case VOLUME:
                        if (selectedCloud &gt;=0){
                            grainCloud-&gt;at(selectedCloud)-&gt;setVolumeDb(value);
                        }
                    default:
                        break;
                }
                paramString = &quot;&quot;;
            }
           // cout &lt;&lt; &quot;enter key caught&quot; &lt;&lt; endl;
            break;
            
            
            
            
        case 27: //esc key
            cleaningFunction();
            exit(1);
            break;
            
        case &#039;Q&#039;://spatialization
        case &#039;q&#039;:  
                      break;
            
        case &#039;O&#039;:
        case &#039;o&#039;:
            toggleFullScreen();
            break;
            
        case &#039;T&#039;:
        case &#039;t&#039;:
            paramString = &quot;&quot;;
            if (selectedCloud &gt;=0){
                if (currentParam != SPATIALIZE){
                    currentParam = SPATIALIZE;
                }else{
                    if (modkey == GLUT_ACTIVE_SHIFT){
                        if (selectedCloud &gt;=0){
                            int theSpat = grainCloud-&gt;at(selectedCloud)-&gt;getSpatialMode();
                            grainCloud-&gt;at(selectedCloud)-&gt;setSpatialMode(theSpat - 1,-1);
                            
                        }
                    }else{
                        if (selectedCloud &gt;=0){
                            int theSpat = grainCloud-&gt;at(selectedCloud)-&gt;getSpatialMode();
                            grainCloud-&gt;at(selectedCloud)-&gt;setSpatialMode(theSpat + 1,-1);
                        }
                    }
                }
            }
            break;
            
        case &#039;S&#039;://overlap control 
        case &#039;s&#039;:
            paramString = &quot;&quot;;
            if (currentParam != OVERLAP){
                currentParam = OVERLAP;
            }else{
                if (modkey == GLUT_ACTIVE_SHIFT){
                    if (selectedCloud &gt;=0){
                        float theOver =  grainCloud-&gt;at(selectedCloud)-&gt;getOverlap();
                        grainCloud-&gt;at(selectedCloud)-&gt;setOverlap(theOver - 0.01f);
                    }
                }else{
                    if (selectedCloud &gt;=0){
                        float theOver =  grainCloud-&gt;at(selectedCloud)-&gt;getOverlap();
                        grainCloud-&gt;at(selectedCloud)-&gt;setOverlap(theOver + 0.01f);
                    }
                }
            }
            break;
        case &#039;R&#039;:
        case &#039;r&#039;:
            if (selectedCloud &gt;=0){
                currentParam = MOTIONXY;
            }
            //toggle selection modes
            dragMode = RESIZE;
            break;
        case &#039;F&#039;://direction
        case &#039;f&#039;:
            paramString = &quot;&quot;;
            if (selectedCloud &gt;=0){
                if (currentParam != DIRECTION){
                    currentParam = DIRECTION;
                }else{
                    if (modkey == GLUT_ACTIVE_SHIFT){
                        if (selectedCloud &gt;=0){
                            int theDir = grainCloud-&gt;at(selectedCloud)-&gt;getDirection();
                            grainCloud-&gt;at(selectedCloud)-&gt;setDirection(theDir - 1);
                            
                        }
                    }else{
                        if (selectedCloud &gt;=0){
                            int theDir = grainCloud-&gt;at(selectedCloud)-&gt;getDirection();
                            grainCloud-&gt;at(selectedCloud)-&gt;setDirection(theDir + 1);
                        }
                    }
                }
            }
            if (selectedRect &gt;=0){
                soundViews-&gt;at(selectedRect)-&gt;toggleOrientation();
            }
            //cerr &lt;&lt; &quot;Looking from the front&quot; &lt;&lt; endl;
            break;
        case &#039;P&#039;://waveform display on/off
        case &#039;p&#039;:

//            for (int i = 0; i &lt; soundViews-&gt;size();i++){
//                soundViews-&gt;at(i)-&gt;toggleWaveDisplay();
//            }
            break;
        case &#039;W&#039;://window editing for grain
        case &#039;w&#039;:
            paramString = &quot;&quot;;
            if (currentParam != WINDOW){
                currentParam = WINDOW;
            }else{
                if (modkey == GLUT_ACTIVE_SHIFT){
                    if (selectedCloud &gt;=0){
                        int theWin = grainCloud-&gt;at(selectedCloud)-&gt;getWindowType();
                        grainCloud-&gt;at(selectedCloud)-&gt;setWindowType(theWin - 1);

                    }
                }else{
                    if (selectedCloud &gt;=0){
                        int theWin = grainCloud-&gt;at(selectedCloud)-&gt;getWindowType();
                        grainCloud-&gt;at(selectedCloud)-&gt;setWindowType(theWin + 1);
                    }
                }
            }
            
            break;
            
        case &#039;B&#039;:
        case &#039;b&#039;:
            //cloud volume
            paramString = &quot;&quot;;
            if (currentParam != VOLUME){
                currentParam = VOLUME;
            }else{
                if (modkey == GLUT_ACTIVE_SHIFT){
                    if (selectedCloud &gt;=0){
                        float theVol = grainCloud-&gt;at(selectedCloud)-&gt;getVolumeDb();
                        grainCloud-&gt;at(selectedCloud)-&gt;setVolumeDb(theVol - 0.5f);
                    }
                }else{
                    if (selectedCloud &gt;=0){
                        float theVol = grainCloud-&gt;at(selectedCloud)-&gt;getVolumeDb();
                        grainCloud-&gt;at(selectedCloud)-&gt;setVolumeDb(theVol + 0.5f);
                    }
                }
            }

            
            break;
            
        case &#039;/&#039;://switch to menu view
        case &#039;?&#039;:
            menuFlag = !menuFlag;
        
            break;
        case &#039;G&#039;:
        case &#039;g&#039;:
            paramString = &quot;&quot;;
            deselect(RECT);
            if (grainCloud != NULL){
                if (modkey == GLUT_ACTIVE_SHIFT){
                    if (grainCloud-&gt;size() &gt; 0){
                        grainCloud-&gt;pop_back();
                        grainCloudVis-&gt;pop_back();
                        numClouds-=1;
                        //cout &lt;&lt; &quot;cloud removed&quot; &lt;&lt; endl;
                    }
                    if (numClouds == 0){
                        selectedCloud = -1;
                    }else{
                        //still have a cloud so select
                        selectedCloud = numClouds-1;
                        grainCloudVis-&gt;at(selectedCloud)-&gt;setSelectState(true);
                    }
                    break;
                    
                }else{
                    int numVoices = 8;//initial number of voices
                    int idx = grainCloud-&gt;size();
                    if (selectedCloud &gt;=0){
                        if (numClouds &gt; 0){
                            grainCloudVis-&gt;at(selectedCloud)-&gt;setSelectState(false);
                        }
                    }
                    selectedCloud = idx;
                    //create audio
                    grainCloud-&gt;push_back(new GrainCluster(mySounds,numVoices));
                    //create visualization
                    grainCloudVis-&gt;push_back(new GrainClusterVis(mouseX,mouseY,numVoices,soundViews));
                    //select new cloud
                    grainCloudVis-&gt;at(idx)-&gt;setSelectState(true);
                    //register visualization with audio
                    grainCloud-&gt;at(idx)-&gt;registerVis(grainCloudVis-&gt;at(idx));
                    //grainCloud-&gt;at(idx)-&gt;toggleActive();
                    numClouds+=1;
                }
                //                        cout &lt;&lt; &quot;cloud added&quot; &lt;&lt; endl;
                //grainControl-&gt;newCluster(mouseX,mouseY,1);
            }
          
            break;
        case &#039;V&#039;: //grain voices (add, delete)
        case &#039;v&#039;:
            paramString = &quot;&quot;;
            if (currentParam != NUMGRAINS){
                currentParam = NUMGRAINS;
            }else{
                if (modkey == GLUT_ACTIVE_SHIFT){
                    if (selectedCloud &gt;=0){
                        if (grainCloud)
                            grainCloud-&gt;at(selectedCloud)-&gt;removeGrain();
                        //cout &lt;&lt; &quot;grain removed&quot; &lt;&lt; endl;
                    }
                    
                }else{
                    if (selectedCloud &gt;=0){
                        if (grainCloud)
                            grainCloud-&gt;at(selectedCloud)-&gt;addGrain();
                        //cout &lt;&lt; &quot;grain added&quot; &lt;&lt; endl;
                    }
                }
            }
            break;
        
        case &#039;D&#039;:
        case &#039;d&#039;:
            paramString = &quot;&quot;;
            if (currentParam != DURATION){
                currentParam = DURATION;
            }else{
                if (modkey == GLUT_ACTIVE_SHIFT){
                    if (selectedCloud &gt;=0){
                        float theDur = grainCloud-&gt;at(selectedCloud)-&gt;getDurationMs();
                        grainCloud-&gt;at(selectedCloud)-&gt;setDurationMs(theDur - 5.0f);
                    }
                }else{
                    if (selectedCloud &gt;=0){
                        float theDur = grainCloud-&gt;at(selectedCloud)-&gt;getDurationMs();
                        grainCloud-&gt;at(selectedCloud)-&gt;setDurationMs(theDur + 5.0f);
                    }
                }
            }
            break;    
        case &#039;I&#039;:
        case &#039;i&#039;:
            break;
            
            
        case &#039;L&#039;:
        case &#039;l&#039;:
            paramString = &quot;&quot;;
            if (currentParam != P_LFO_FREQ){
                currentParam = P_LFO_FREQ;
            }else{
                if (modkey == GLUT_ACTIVE_SHIFT){
                    if (selectedCloud &gt;=0){
                        float theLFOFreq = grainCloud-&gt;at(selectedCloud)-&gt;getPitchLFOFreq();
                        grainCloud-&gt;at(selectedCloud)-&gt;setPitchLFOFreq(theLFOFreq - 0.01f);
                    }
                }else{
                    if (selectedCloud &gt;=0){
                        float theLFOFreq = grainCloud-&gt;at(selectedCloud)-&gt;getPitchLFOFreq();
                        grainCloud-&gt;at(selectedCloud)-&gt;setPitchLFOFreq(theLFOFreq + 0.01f);
                    }
                }
            }
            break;
            
        case &#039;K&#039;:
        case &#039;k&#039;:
            paramString = &quot;&quot;;
            if (currentParam != P_LFO_AMT){
                currentParam = P_LFO_AMT;
            }else{
                if (modkey == GLUT_ACTIVE_SHIFT){
                    if (selectedCloud &gt;=0){
                        float theLFOAmt = grainCloud-&gt;at(selectedCloud)-&gt;getPitchLFOAmount();
                        grainCloud-&gt;at(selectedCloud)-&gt;setPitchLFOAmount(theLFOAmt - 0.001f);
                    }
                }else{
                    if (selectedCloud &gt;=0){
                        float theLFOAmnt = grainCloud-&gt;at(selectedCloud)-&gt;getPitchLFOAmount();
                        grainCloud-&gt;at(selectedCloud)-&gt;setPitchLFOAmount(theLFOAmnt + 0.001f);
                    }
                }
            }
            break;
        case &#039;H&#039;:
        case &#039;h&#039;:
            break;
        case &#039; &#039;://add delete
            
            break;
            
        case &#039;X&#039;:
        case &#039;x&#039;:
            paramString = &quot;&quot;;
            if (selectedCloud &gt;= 0){
                currentParam = MOTIONX;
            }
            break;
        case &#039;Y&#039;:
        case &#039;y&#039;:
            paramString = &quot;&quot;;
            if (selectedCloud &gt;= 0){
                currentParam = MOTIONY;
            }
            break;
            
        case &#039;Z&#039;:
        case &#039;z&#039;:
            paramString = &quot;&quot;;
            if (currentParam != PITCH){
                currentParam = PITCH;
            }else{
                if (modkey == GLUT_ACTIVE_SHIFT){
                    if (selectedCloud &gt;=0){
                        float thePitch =  grainCloud-&gt;at(selectedCloud)-&gt;getPitch();
                        grainCloud-&gt;at(selectedCloud)-&gt;setPitch(thePitch - 0.01f);
                    }
                }else{
                    if (selectedCloud &gt;=0){
                        float thePitch =  grainCloud-&gt;at(selectedCloud)-&gt;getPitch();
                        grainCloud-&gt;at(selectedCloud)-&gt;setPitch(thePitch + 0.01f);
                    }
                }
            }
            break;
                        
        case &#039;-&#039;:
        case &#039;_&#039;:
            paramString.insert(0,&quot;-&quot;);
            break;
        case 127://delete selected
            if (paramString == &quot;&quot;){
                if (selectedCloud &gt;=0){
                    grainCloud-&gt;erase(grainCloud-&gt;begin() + selectedCloud);
                    grainCloudVis-&gt;erase(grainCloudVis-&gt;begin() + selectedCloud);
                    selectedCloud = -1;
                    numClouds-=1;
                }
            }else{
                if (paramString.size () &gt; 0)  paramString.resize (paramString.size () - 1);
            }
                    
            break;
        case &#039;A&#039;:
        case &#039;a&#039;:
            paramString = &quot;&quot;;
            if (selectedCloud &gt;=0){
                grainCloud-&gt;at(selectedCloud)-&gt;toggleActive();
            }
            break;
        case &#039;=&#039;:
        case &#039;+&#039;:
            
           
                           
            break;
        case &#039;,&#039;:
        case &#039;&lt;&#039;:
            break;
        case &#039;&gt;&#039;:
            break;
            
        default:
            //cout &lt;&lt; &quot;key pressed &quot; &lt;&lt; key &lt;&lt; endl;
            break;
    }
    glutPostRedisplay( );
}


//-----------------------------------------------------------------------------
// Handle mouse clicks, etc.
//-----------------------------------------------------------------------------


//handle deselections
void deselect(int shapeType){
    switch (shapeType){
        case CLOUD:
            if (selectedCloud &gt;=0){
                grainCloudVis-&gt;at(selectedCloud)-&gt;setSelectState(false);
                //reset selected cloud
                selectedCloud = -1;
                //cout &lt;&lt; &quot;deselecting cloud&quot; &lt;&lt;endl;
            }
            
        case RECT:
            if (selectedRect &gt;= 0){
                //cout &lt;&lt; &quot;deselecting rect&quot; &lt;&lt; endl;
                soundViews-&gt;at(selectedRect)-&gt;setSelectState(false);
                selectedRect = -1;
            }
            
    }
}



//mouse clicks
void mouseFunc(int button, int state, int x, int y){
    //cout &lt;&lt; &quot;button &quot; &lt;&lt; button &lt;&lt; endl;

            //look for selections if button is down
            if ((button == GLUT_LEFT_BUTTON) || (button == GLUT_RIGHT_BUTTON) &amp;&amp; (state == GLUT_DOWN)){
                
                paramString = &quot;&quot;;
                
                //hide menu
                if (menuFlag == true)
                    menuFlag = false;
                
                deselect(CLOUD);
                //deselect existing selections
                deselect(RECT);
                //exit parameter editing
                currentParam = -1;
                
                lastDragX = veryHighNumber;
                lastDragY = veryHighNumber;
                //first check grain clouds to see if we have selection
                for (int i = 0; i &lt; grainCloudVis-&gt;size(); i++){
                    if (grainCloudVis-&gt;at(i)-&gt;select(mouseX, mouseY) == true){
                        grainCloudVis-&gt;at(i)-&gt;setSelectState(true);
                        selectedCloud = i;
                        break;
                    }            
                }
                
                
                //clear selection buffer
                if (selectionIndices)
                    delete selectionIndices;
                //allocate new buffer
                selectionIndices = new vector&lt;int&gt;;
                selectionIndex = 0;
                //if grain cloud is not selected - search for rectangle selection
                if (selectedCloud &lt; 0){
                    //search for selections
                    resizeDir = false;//set resize direction to horizontal
                    for (int i = 0; i &lt; soundViews-&gt;size(); i++){
                        if (soundViews-&gt;at(i)-&gt;select(mouseX,mouseY) == true){
                            selectionIndices-&gt;push_back(i);
                            //soundViews-&gt;at(i)-&gt;setSelectState(true);
                            //selectedRect = i;
                            //break;
                        }
                    }
                    
                    if (selectionIndices-&gt;size() &gt; 0){
                        selectedRect = selectionIndices-&gt;at(0);
                        soundViews-&gt;at(selectedRect)-&gt;setSelectState(true);
                    }
                }
                
            }

    
//    //handle button up
//    if ((button == GLUT_LEFT_BUTTON) &amp;&amp; (state == GLUT_UP)){
//        lastDragX = -1;
//        lastDragY = -1;
//        dragMode = MOVE;
//    }
    
}

//-----------------------------------------------------------------------------
// Handle mouse movement during button press (drag)
//-----------------------------------------------------------------------------

void mouseDrag(int x, int y)
{
    //update mouse coordinates based on drag position
    updateMouseCoords(x,y);
    int xDiff = 0;
    int yDiff = 0;
    
    if (selectedCloud &gt;= 0){
        grainCloudVis-&gt;at(selectedCloud)-&gt;updateCloudPosition(mouseX,mouseY);
    }else{
        
        switch (dragMode) {
            case MOVE:
                if( (lastDragX != veryHighNumber) &amp;&amp; (lastDragY != veryHighNumber)){
                    
                    if (selectedRect &gt;=0){                    //movement case                    
                        soundViews-&gt;at(selectedRect)-&gt;move(mouseX - lastDragX,mouseY - lastDragY);
                    }
                }
                lastDragX = mouseX;
                lastDragY = mouseY;
                break;
                
            case RESIZE:
                if( (lastDragX != veryHighNumber) &amp;&amp; (lastDragY != veryHighNumber)){
                    //cout &lt;&lt; &quot;drag ok&quot; &lt;&lt; endl;
                    //for width height - use screen coords
                    
                    if (selectedRect &gt;= 0){
                        xDiff = x - lastDragX;
                        yDiff = y - lastDragY;
                        //get width and height
                        float newWidth = soundViews-&gt;at(selectedRect)-&gt;getWidth();
                        float newHeight = soundViews-&gt;at(selectedRect)-&gt;getHeight();
                        
                        int thresh = 0;
                        //check motion mag
                        if (xDiff &lt; -thresh){
                            newWidth = newWidth * 0.8 + 0.2*(newWidth * (1.1 + abs(xDiff/50.0)));
                        }else{
                            if (xDiff &gt; thresh)
                                newWidth = newWidth * 0.8 + 0.2*(newWidth * (0.85 - abs(xDiff/50.0)));
                        }
                        if (yDiff &gt; thresh){
                            newHeight = newHeight * 0.8 + 0.2*(newHeight * (1.1 + abs(yDiff/50.0)));
                        }else{
                            if (yDiff &lt; -thresh)
                         newHeight = newHeight * 0.8 + 0.2*(newHeight * (0.85 - abs(yDiff/50.0)));
                        }
                            
                            //update width and height
                        soundViews-&gt;at(selectedRect)-&gt;setWidthHeight(newWidth,newHeight);
                            
                    }
                    
                   
                }   
                lastDragX = x;
                lastDragY = y;
                break;
            default:
                break;
        }
    }
    
}



//-----------------------------------------------------------------------------
// Handle mouse movement anytime
//-----------------------------------------------------------------------------

void mousePassiveMotion(int x, int y)
{
    updateMouseCoords(x,y);
    
    
        if (selectedCloud &gt;=0){
            switch (currentParam) {
                case MOTIONX:
                    grainCloudVis-&gt;at(selectedCloud)-&gt;setXRandExtent(mouseX);
                    break;
                case MOTIONY:
                    grainCloudVis-&gt;at(selectedCloud)-&gt;setYRandExtent(mouseY);
                    break;
                case MOTIONXY:
                    grainCloudVis-&gt;at(selectedCloud)-&gt;setRandExtent(mouseX,mouseY);
                    break;
                default:
                    break;
            }
        }
    //            case NUMGRAINS:
    //                break;
    //            case DURATION:
    //                grainCloud-&gt;at(selectedCloud)-&gt;setDurationMs((mouseY/screenHeight)*4000.0f);
    //            
    //            default:
    //                break;
    //        }
    //    }
    //process rectangles
    //    for (int i = 0; i &lt; soundViews-&gt;size(); i++)
    //        soundViews-&gt;at(i)-&gt;procMovement(x, y);
    //    
}






//-----------------------------------------------------------------------------//
// MAIN
//-----------------------------------------------------------------------------//
int main (int argc, char ** argv)
{
    //init random number generator
    srand(time(NULL));
    //start time
    
    //-------------Graphics Initialization--------//
    
    // initialize GLUT
    glutInit( &amp;argc, argv );
    
    // initialize graphics
    initialize();
    
    
    
    
    
    // load sounds

    
    mkdir(g_programPathUser.c_str(), 01777);
    mkdir(g_audioPathUser.c_str(), 01777);

    DIR* rep = NULL;
    struct dirent* fichierLu = NULL; /* Déclaration d&#039;un pointeur vers la structure dirent. */
    g_audioPath = g_audioPathUser;    
    rep = opendir(g_audioPathUser.c_str());
     
    fichierLu = readdir(rep); /* On lit le premier répertoire du dossier (.) */
    fichierLu = readdir(rep); /* On lit le deuxieme répertoire du dossier (..) */
    if ((fichierLu = readdir(rep)) == NULL) {
        cout &lt;&lt; &quot;Pas d&#039;échantillons dans le répertoire utilisateur, chargement des sons par défaut&quot; &lt;&lt; endl;    
        g_audioPath = g_audioPathDefault;
        }

    AudioFileSet newFileMgr;

    if (newFileMgr.loadFileSet(g_audioPath) == 1){
       goto cleanup;
    }
  
    mySounds = newFileMgr.getFileVector();
    cout &lt;&lt; &quot;Succes du chargement des sons...&quot; &lt;&lt; endl;    
    
    
    
    //create visual representation of sounds    
    soundViews = new vector&lt;SoundRect *&gt;;
    for (int i = 0; i &lt; mySounds-&gt;size(); i++)
    {
        soundViews-&gt;push_back(new SoundRect());
        soundViews-&gt;at(i)-&gt;associateSound(mySounds-&gt;at(i)-&gt;wave,mySounds-&gt;at(i)-&gt;frames,mySounds-&gt;at(i)-&gt;channels);
    }
    
    //init grain cloud vector and corresponding view vector
    grainCloud = new vector&lt;GrainCluster *&gt;;
    grainCloudVis = new vector&lt;GrainClusterVis *&gt;;
    
    
    
    //-------------Audio Configuration-----------//
    
    //configure RtAudio
    //create the object
    try {
        theAudio = new MyRtAudio(1,MY_CHANNELS, MY_SRATE, &amp;g_buffSize, MY_FORMAT,true);
    } catch (RtError &amp; err) {
        err.printMessage();
        exit(1);
    }    
    try
    {
        //open audio stream/assign callback
        theAudio-&gt;openStream(&amp;audioCallback);
        //get new buffer size
        g_buffSize = theAudio-&gt;getBufferSize();
        //start audio stream
        theAudio-&gt;startStream();
        //report latency
        theAudio-&gt;reportStreamLatency();        
        
    }catch (RtError &amp; err )
    {
        err.printMessage();
        goto cleanup;
    }
    
    
    
    //start graphics
    // let GLUT handle the current thread from here
    glutMainLoop();
    
    cout &lt;&lt;&quot;Quelque chose n&#039;a pas ete correctement...on ne devrait pas être ici&quot; &lt;&lt; endl;
    
    
    //cleanup routine
cleanup:
    cleaningFunction();
    
    // done
    return 0;
    
}

