Mercurial > hg > screen-ui
view src/melodyTriangle.cpp @ 18:9a414ea6880d
Added colour coding of voice status.
author | samer |
---|---|
date | Tue, 31 Jan 2012 15:49:40 +0000 |
parents | add71da95cb4 |
children | 055d7524bae4 |
line wrap: on
line source
#include "melodyTriangle.h" #include <GLUT/GLUT.h> #define BUFFER_ZONE 64 // have to drag this far to snap out of triange. /* /birth id /death id /start id /stop id /track id x y left right top bottom area /tempo */ melodyTriangle::melodyTriangle(const char *host, int port, int numVoices, bool enableKeys,int voiceIdOffset,int receivePort){ printf("in constructor: %s %i %i %i %i %i\n",host,port,numVoices,enableKeys,voiceIdOffset,receivePort); this->numVoices=numVoices; this->enableKeys=enableKeys; this->voiceIdOffset=voiceIdOffset; //voices=*Voice[numVoices]; sender.setup( host,port ); receiver.setup( receivePort ); { ofxOscMessage m; m.setAddress( "/reply_to" ); m.addIntArg( receivePort ); sender.sendMessage( m ); printf("sent /reply_to %i\n",receivePort); } } //-------------------------------------------------------------- void melodyTriangle::setup(){ ofSetCircleResolution(100); ofBackground(0,0,0); ofSetWindowTitle("Melody Triangle"); // if vertical sync is off, we can go a bit fast... // this caps the framerate at 40fps. ofSetFrameRate(40); ofEnableSmoothing(); // Set up triange coordinates. // NB. whatever happens here, the triangle must be // isosceles and left-right symmetric around x=x1. // Otherwise the clipping won't work triangleHeight=ofGetHeight()*0.75; x1=ofGetWidth()/2; y1=(ofGetHeight()-triangleHeight)/2; x2=ofGetWidth()/2-triangleHeight/sqrt(3); y2=ofGetHeight()-(ofGetHeight()-triangleHeight)/2; x3=ofGetWidth()/2+triangleHeight/sqrt(3); y3=y2; // used for clipping DX13=x3-x1; DY13=y3-y1; SQLEN13=DX13*DX13+DY13*DY13; sendCalibrate(); for (int i=0;i<numVoices;i++){ voices[i]=new Voice(i+1+voiceIdOffset,x2+15,y1+20+i*30); } voiceGrabbed=-1; } void melodyTriangle::sendCalibrate(){ ofxOscMessage m; m.setAddress( "/calibrate" ); m.addIntArg( x1 ); m.addIntArg( y1 ); m.addIntArg( x2 ); m.addIntArg( y2 ); m.addIntArg( x3 ); m.addIntArg( y3 ); sender.sendMessage( m ); printf("sent /calibrate %i %i %i %i %i %i\n",x1,y1,x2,y2,x3,y3); } void melodyTriangle::sendPeriod(int id, int num, int den){ ofxOscMessage m; m.setAddress("/period"); m.addIntArg(id); m.addIntArg(num); m.addIntArg(den); sender.sendMessage(m); printf("sent /period %i %i %i\n",id,num,den); } void melodyTriangle::sendShift(int id, int num, int den){ ofxOscMessage m; m.setAddress("/shift"); m.addIntArg(id); m.addIntArg(num); m.addIntArg(den); sender.sendMessage(m); printf("sent /shift %i %i %i\n",id,num,den); } void melodyTriangle::sendOctave(int id, int oct){ ofxOscMessage m; m.setAddress("/octave"); m.addIntArg(id); m.addIntArg(oct); sender.sendMessage(m); printf("sent /octave %i %i\n",id,oct); } void melodyTriangle::sendAmplitude(int id, float amp){ ofxOscMessage m; m.setAddress("/amplitude"); m.addIntArg(id); m.addFloatArg(amp); sender.sendMessage(m); printf("sent /amplitude %i %1.3f\n",id,amp); } //-------------------------------------------------------------- void melodyTriangle::update(){ while( receiver.hasWaitingMessages() ) { // get the next message ofxOscMessage m; receiver.getNextMessage( &m ); if (m.getAddress()=="/notify") { int id=m.getArgAsInt32(0)-1; string st=m.getArgAsString(1); if (id>=0 && id<numVoices) { Voice *v=voices[id]; if (st=="received") v->status=Voice::clear; else if (st=="pending") v->status=Voice::pending; else if (st=="requested") v->status=Voice::waiting; else cout << "** unrecognised voice status: " << st << ".\n"; } else { cout << "** voice id "<<id<<" out of range.\n"; } } else { string msg_string; msg_string = m.getAddress(); msg_string += ": "; for ( int i=0; i<m.getNumArgs(); i++ ) { // get the argument type msg_string += m.getArgTypeName( i ); msg_string += ":"; // display the argument - make sure we get the right type if( m.getArgType( i ) == OFXOSC_TYPE_INT32 ) msg_string += ofToString( m.getArgAsInt32( i ) ); else if( m.getArgType( i ) == OFXOSC_TYPE_FLOAT ) msg_string += ofToString( m.getArgAsFloat( i ) ); else if( m.getArgType( i ) == OFXOSC_TYPE_STRING ) msg_string += m.getArgAsString( i ); else msg_string += "unknown"; } cout<< msg_string << "\n"; } } } bool melodyTriangle::clipToTriangle(int *x, int *y) { bool clipped; if (*y>y2) { // off the bottom clipped=true; *y=y2; if (*x<x2) *x=x2; else if (*x>x3) *x=x3; } else { // have to be a bit cleverer bool reflect=false; if (*x<x1) { // work in reflected coordinates reflect=true; *x=2*x1-*x; } int dx=(*x-x1), dy=(*y-y1); // deltas from top if (dx*DY13 > dy*DX13) { // (x,y) must be somewhere right of triangle now clipped=true; int dp=dx*DX13 + dy*DY13; if (dp<0) { *x=x1; *y=y1; } // off the top else if (dp>SQLEN13) { *x=x3; *y=y3; } // off the bottom right else { // project onto right edge *x=x1+dp*DX13/SQLEN13; *y=y1+dp*DY13/SQLEN13; } } else { clipped=false; } if (reflect) *x=2*x1 - *x; // reflect back if necessary } return clipped; } void melodyTriangle::sendPosition(Voice v){ ofxOscMessage m; ///track id x y left right top bottom area m.setAddress( "/track2d" ); m.addIntArg( v.id ); m.addIntArg( v.posx ); m.addIntArg( v.posy ); sender.sendMessage( m ); printf("sent - /track2d %i %i %i\n",v.id,v.posx,v.posy); } //-------------------------------------------------------------- void melodyTriangle::draw(){ bool constrained=false; bool sendStart=false; if (voiceGrabbed!=-1){ Voice *vg=voices[voiceGrabbed]; if (mouseX!=vg->posx || mouseY!=vg->posy){ int clipx=mouseX, clipy=mouseY; bool clipped=clipToTriangle(&clipx,&clipy); if (vg->inTriangle) { if (clipped) { // check how far we clipped if (ofDist(clipx, clipy, mouseX, mouseY) > BUFFER_ZONE) { // if far enough, we pop out of triangle and send // /death <id> ofxOscMessage m; m.setAddress( "/death" ); m.addIntArg( vg->id ); sender.sendMessage( m ); printf("sent /death %i \n",vg->id); vg->posx=mouseX; vg->posy=mouseY; vg->inTriangle=false; vg->status=Voice::clear; } else { // otherwise, we move to clipped point constrained=true; vg->posx=clipx; vg->posy=clipy; } } else { // not clipped; normal move vg->posx=mouseX; vg->posy=mouseY; } } else { // token was outside triangle vg->posx=mouseX; vg->posy=mouseY; if (!clipped){ // ie mouse now in triangle //birth id ofxOscMessage m; m.setAddress( "/birth" ); m.addIntArg( vg->id ); sender.sendMessage( m ); printf("sent /birth %i \n",vg->id); sendOctave(vg->id,vg->octave); sendAmplitude(vg->id,vg->amplitude); sendStart=true; vg->inTriangle=true; } } if (vg->inTriangle){ sendPosition(*vg); vg->status=Voice::moved; if (sendStart && vg->isActive){ ofxOscMessage m; ///track id x y left right top bottom area m.setAddress( "/start" ); m.addIntArg( vg->id ); sender.sendMessage( m ); printf("sent /start %i \n",vg->id); } } } }; //let's draw our triangle ofSetLineWidth(2); ofSetColor(96,96,96); ofFill(); ofTriangle(x1, y1, x2, y2, x3, y3); if (constrained) ofSetColor(255,96,96); // draw smooth edge, brighter if a token is constrained ofNoFill(); ofTriangle(x1, y1, x2, y2, x3, y3); for (int i=0; i<numVoices; i++){ (*voices[i]).draw(); } } //-------------------------------------------------------------- void melodyTriangle::keyPressed (int key){ //printf("key %i",key); if (enableKeys){ switch (key) { case ' ': { ofxOscMessage m; m.setAddress( "/marker" ); sender.sendMessage(m); printf("sent /marker\n"); break; } case '1': case '2': case '3': case '4': { int tempo=30 + 30*(key-'1'); ofxOscMessage m; m.setAddress( "/tempo" ); m.addIntArg(tempo); sender.sendMessage( m ); printf("sent /tempo %d\n",tempo); } break; case 'c': sendCalibrate(); break; default: { // otherwise, send key to all active voices for (int i=0; i<numVoices; i++){ if (voices[i]->isInVoice(mouseX,mouseY)){ Voice *v=voices[i]; switch (key) { case 'a': { ofxOscMessage m; const char *addr = v->isActive ? "/stop" : "/start"; v->isActive=!v->isActive; m.setAddress(addr); m.addIntArg(v->id ); sender.sendMessage( m ); printf("sent %s %i \n",addr,v->id); break; } case OF_KEY_LEFT: sendShift(v->id,-1,2); break; case OF_KEY_RIGHT: sendShift(v->id,1,2); break; case OF_KEY_UP: sendPeriod(v->id,1,2); break; case OF_KEY_DOWN: sendPeriod(v->id,2,1); break; case '.': sendPeriod(v->id,1,3); break; case ',': sendPeriod(v->id,3,1); break; case '+': sendOctave(v->id, ++v->octave); break; case '-': sendOctave(v->id, --v->octave); break; case '*': sendAmplitude(v->id, v->louder()); break; case '/': sendAmplitude(v->id, v->quieter()); break; default: printf("unrecognised key: %d.\n",key); } } } } } } } //-------------------------------------------------------------- void melodyTriangle::keyReleased (int key){ } //-------------------------------------------------------------- void melodyTriangle::mouseMoved(int x, int y ){ for (int i=0; i<numVoices;i++){ voices[i]->highlight = voices[i]->isInVoice(x,y); } } //-------------------------------------------------------------- void melodyTriangle::mouseDragged(int x, int y, int button){ } //-------------------------------------------------------------- void melodyTriangle::mousePressed(int x, int y, int button){ for (int i=0; i<numVoices;i++){ if (voices[i]->isInVoice(x,y)){ voiceGrabbed=i; //printf("grabbed %i",voiceGrabbed); }else{ //printf("didnt grab %i",i); } } } //-------------------------------------------------------------- void melodyTriangle::mouseReleased(int x, int y, int button){ //printf("released %i",voiceGrabbed); voiceGrabbed=-1; } //-------------------------------------------------------------- void melodyTriangle::windowResized(int w, int h){ }