annotate src/melodyTriangle.cpp @ 22:4dcc4312b5fa

Bit of a tidy up, adding text display, added full screen toggle and window resize handler.
author samer
date Thu, 02 Feb 2012 18:17:24 +0000
parents 055d7524bae4
children 460c05dd74d0
rev   line source
hekeus@6 1 #include "melodyTriangle.h"
hekeus@6 2 #include <GLUT/GLUT.h>
hekeus@6 3
samer@19 4 #define BUFFER_ZONE 50 // have to drag this far to snap out of triange.
hekeus@6 5 /*
hekeus@6 6 /birth id
hekeus@6 7 /death id
hekeus@6 8 /start id
hekeus@6 9 /stop id
hekeus@6 10 /track id x y left right top bottom area
hekeus@6 11 /tempo
hekeus@6 12
hekeus@6 13
hekeus@6 14 */
samer@22 15
samer@22 16 melodyTriangle::melodyTriangle(const char *host, int port, int numVoices,
samer@22 17 bool enableKeys,int voiceIdOffset,int receivePort):
samer@22 18 numVoices(numVoices), enableKeys(enableKeys), receivePort(receivePort),
samer@22 19 display_msg(""),
samer@22 20 display_frames(0)
samer@22 21 {
hekeus@8 22 printf("in constructor: %s %i %i %i %i %i\n",host,port,numVoices,enableKeys,voiceIdOffset,receivePort);
samer@22 23 for (int i=0;i<numVoices;i++) voices[i]=new Voice(i+1+voiceIdOffset);
samer@22 24
hekeus@6 25 sender.setup( host,port );
hekeus@8 26 receiver.setup( receivePort );
samer@22 27 display_font.loadFont("/System/Library/Fonts/HelveticaLight.ttf",32);
hekeus@6 28 }
hekeus@6 29
samer@22 30 melodyTriangle::~melodyTriangle() {
samer@22 31 printf("Deleting voice objects...\n");
samer@22 32 for (int i=0;i<numVoices;i++) delete voices[i];
samer@22 33 }
samer@22 34
hekeus@6 35 //--------------------------------------------------------------
hekeus@6 36 void melodyTriangle::setup(){
samer@22 37 ofSetCircleResolution(64);
hekeus@6 38 ofBackground(0,0,0);
hekeus@6 39 ofSetWindowTitle("Melody Triangle");
samer@22 40
samer@18 41 // if vertical sync is off, we can go a bit fast...
samer@18 42 // this caps the framerate at 40fps.
samer@18 43 ofSetFrameRate(40);
samer@18 44 ofEnableSmoothing();
samer@18 45
samer@22 46 sendReplyTo();
samer@22 47
samer@18 48 // Set up triange coordinates.
samer@18 49 // NB. whatever happens here, the triangle must be
samer@18 50 // isosceles and left-right symmetric around x=x1.
samer@18 51 // Otherwise the clipping won't work
samer@22 52 fitTriangleIn(ofGetWidth(),ofGetHeight());
samer@22 53 sendCalibrate();
hekeus@6 54
samer@22 55 for (int i=0;i<numVoices;i++) voices[i]->setPos(x2+voices[i]->radius+i*30,48);
samer@12 56 voiceGrabbed=-1;
samer@12 57 }
samer@12 58
hekeus@6 59 //--------------------------------------------------------------
hekeus@6 60 void melodyTriangle::update(){
samer@22 61 bool sendStart=false;
samer@22 62
samer@22 63 while( receiver.hasWaitingMessages() ) {
hekeus@8 64 // get the next message
hekeus@8 65 ofxOscMessage m;
hekeus@8 66 receiver.getNextMessage( &m );
samer@22 67 handleMessage(m);
hekeus@8 68 }
samer@15 69
samer@22 70 constrained=false;
hekeus@6 71 if (voiceGrabbed!=-1){
samer@14 72 Voice *vg=voices[voiceGrabbed];
samer@14 73 if (mouseX!=vg->posx || mouseY!=vg->posy){
samer@15 74 int clipx=mouseX, clipy=mouseY;
samer@15 75 bool clipped=clipToTriangle(&clipx,&clipy);
samer@15 76
samer@15 77 if (vg->inTriangle) {
hekeus@6 78
samer@15 79 if (clipped) {
samer@15 80 // check how far we clipped
samer@15 81 if (ofDist(clipx, clipy, mouseX, mouseY) > BUFFER_ZONE) {
samer@15 82 // if far enough, we pop out of triangle and send
samer@15 83 // /death <id>
samer@15 84 ofxOscMessage m;
samer@15 85 m.setAddress( "/death" );
samer@15 86 m.addIntArg( vg->id );
samer@15 87 sender.sendMessage( m );
samer@22 88
samer@15 89 printf("sent /death %i \n",vg->id);
samer@15 90 vg->posx=mouseX;
samer@15 91 vg->posy=mouseY;
samer@15 92 vg->inTriangle=false;
samer@18 93 vg->status=Voice::clear;
samer@15 94 } else {
samer@15 95 // otherwise, we move to clipped point
samer@15 96 constrained=true;
samer@15 97 vg->posx=clipx;
samer@15 98 vg->posy=clipy;
samer@15 99 }
samer@15 100 } else { // not clipped; normal move
samer@15 101 vg->posx=mouseX;
samer@15 102 vg->posy=mouseY;
samer@15 103 }
samer@15 104 } else { // token was outside triangle
samer@15 105 vg->posx=mouseX;
samer@15 106 vg->posy=mouseY;
samer@15 107 if (!clipped){ // ie mouse now in triangle
samer@15 108 //birth id
hekeus@7 109
samer@10 110 ofxOscMessage m;
samer@15 111 m.setAddress( "/birth" );
samer@14 112 m.addIntArg( vg->id );
samer@10 113 sender.sendMessage( m );
samer@15 114
samer@15 115 printf("sent /birth %i \n",vg->id);
samer@15 116 sendOctave(vg->id,vg->octave);
samer@15 117 sendAmplitude(vg->id,vg->amplitude);
samer@15 118 sendStart=true;
samer@15 119 vg->inTriangle=true;
hekeus@6 120 }
hekeus@6 121 }
hekeus@6 122
samer@14 123 if (vg->inTriangle){
samer@14 124 sendPosition(*vg);
samer@18 125 vg->status=Voice::moved;
samer@15 126 if (sendStart && vg->isActive){
samer@15 127 ofxOscMessage m;
samer@15 128 ///track id x y left right top bottom area
samer@15 129 m.setAddress( "/start" );
samer@15 130 m.addIntArg( vg->id );
samer@15 131 sender.sendMessage( m );
samer@15 132 printf("sent /start %i \n",vg->id);
hekeus@6 133 }
hekeus@6 134 }
hekeus@6 135 }
hekeus@6 136 };
samer@22 137 }
samer@10 138
samer@22 139
samer@22 140
samer@22 141 //--------------------------------------------------------------
samer@22 142 void melodyTriangle::draw(){
samer@11 143 ofSetLineWidth(2);
samer@19 144 ofSetColor(80,80,80);
samer@10 145 ofFill();
samer@10 146 ofTriangle(x1, y1, x2, y2, x3, y3);
samer@12 147 if (constrained) ofSetColor(255,96,96);
samer@10 148
samer@10 149 // draw smooth edge, brighter if a token is constrained
samer@10 150 ofNoFill();
samer@10 151 ofTriangle(x1, y1, x2, y2, x3, y3);
samer@10 152
hekeus@6 153 for (int i=0; i<numVoices; i++){
hekeus@6 154 (*voices[i]).draw();
hekeus@6 155 }
hekeus@6 156
samer@22 157 // display message if any
samer@22 158 if (display_frames>0) {
samer@22 159 ofSetColor(220,220,220);
samer@22 160 display_font.drawString(display_msg,x2,y1+32);
samer@22 161 display_frames--;
samer@22 162 }
hekeus@6 163 }
hekeus@6 164
samer@22 165 bool melodyTriangle::clipToTriangle(int *x, int *y) {
samer@22 166 bool clipped;
samer@22 167
samer@22 168 if (*y>y2) { // off the bottom
samer@22 169 clipped=true;
samer@22 170 *y=y2;
samer@22 171 if (*x<x2) *x=x2;
samer@22 172 else if (*x>x3) *x=x3;
samer@22 173 } else { // have to be a bit cleverer
samer@22 174 bool reflect=false;
samer@22 175 if (*x<x1) { // work in reflected coordinates
samer@22 176 reflect=true;
samer@22 177 *x=2*x1-*x;
samer@22 178 }
samer@22 179
samer@22 180 int dx=(*x-x1), dy=(*y-y1); // deltas from top
samer@22 181 if (dx*DY13 > dy*DX13) {
samer@22 182 // (x,y) must be somewhere right of triangle now
samer@22 183 clipped=true;
samer@22 184 int dp=dx*DX13 + dy*DY13;
samer@22 185 if (dp<0) { *x=x1; *y=y1; } // off the top
samer@22 186 else if (dp>SQLEN13) { *x=x3; *y=y3; } // off the bottom right
samer@22 187 else { // project onto right edge
samer@22 188 *x=x1+dp*DX13/SQLEN13;
samer@22 189 *y=y1+dp*DY13/SQLEN13;
samer@22 190 }
samer@22 191 } else {
samer@22 192 clipped=false;
samer@22 193 }
samer@22 194
samer@22 195 if (reflect) *x=2*x1 - *x; // reflect back if necessary
samer@22 196 }
samer@22 197 return clipped;
samer@22 198 }
samer@22 199
samer@22 200
samer@22 201
samer@22 202 //- Keyboard ----------------------------------------------------------
samer@22 203
samer@22 204 void melodyTriangle::keyReleased(int key){}
hekeus@6 205 void melodyTriangle::keyPressed (int key){
hekeus@6 206 //printf("key %i",key);
hekeus@6 207 if (enableKeys){
samer@12 208 switch (key) {
samer@12 209 case ' ': {
samer@12 210 ofxOscMessage m;
samer@12 211 m.setAddress( "/marker" );
samer@12 212 sender.sendMessage(m);
samer@12 213 printf("sent /marker\n");
samer@12 214 break;
samer@12 215 }
samer@12 216
samer@12 217 case '1':
samer@12 218 case '2':
samer@12 219 case '3':
samer@12 220 case '4': {
samer@12 221 int tempo=30 + 30*(key-'1');
samer@12 222 ofxOscMessage m;
samer@12 223 m.setAddress( "/tempo" );
samer@12 224 m.addIntArg(tempo);
samer@12 225 sender.sendMessage( m );
samer@12 226 printf("sent /tempo %d\n",tempo);
samer@12 227 }
samer@12 228 break;
samer@12 229
samer@22 230 case 'c': sendReplyTo(); sendCalibrate(); break;
samer@22 231 case 'f': ofToggleFullscreen(); break;
samer@12 232
samer@12 233 default: { // otherwise, send key to all active voices
samer@12 234 for (int i=0; i<numVoices; i++){
samer@12 235 if (voices[i]->isInVoice(mouseX,mouseY)){
samer@12 236 Voice *v=voices[i];
samer@12 237 switch (key) {
samer@12 238 case 'a': {
samer@12 239 ofxOscMessage m;
samer@12 240 const char *addr = v->isActive ? "/stop" : "/start";
samer@12 241 v->isActive=!v->isActive;
samer@12 242 m.setAddress(addr);
samer@12 243 m.addIntArg(v->id );
samer@12 244 sender.sendMessage( m );
samer@12 245 printf("sent %s %i \n",addr,v->id);
samer@12 246 break;
samer@12 247 }
samer@12 248 case OF_KEY_LEFT: sendShift(v->id,-1,2); break;
samer@12 249 case OF_KEY_RIGHT: sendShift(v->id,1,2); break;
samer@12 250 case OF_KEY_UP: sendPeriod(v->id,1,2); break;
samer@12 251 case OF_KEY_DOWN: sendPeriod(v->id,2,1); break;
samer@12 252 case '.': sendPeriod(v->id,1,3); break;
samer@12 253 case ',': sendPeriod(v->id,3,1); break;
samer@12 254 case '+': sendOctave(v->id, ++v->octave); break;
samer@12 255 case '-': sendOctave(v->id, --v->octave); break;
samer@13 256 case '*': sendAmplitude(v->id, v->louder()); break;
samer@13 257 case '/': sendAmplitude(v->id, v->quieter()); break;
samer@13 258 default: printf("unrecognised key: %d.\n",key);
samer@12 259 }
hekeus@6 260 }
hekeus@6 261 }
hekeus@6 262 }
hekeus@6 263 }
hekeus@6 264 }
hekeus@6 265 }
hekeus@6 266
samer@22 267 //- Mouse ------------------------------------------------------
hekeus@6 268
samer@22 269 void melodyTriangle::mouseDragged(int x, int y, int button){}
hekeus@6 270 void melodyTriangle::mouseMoved(int x, int y ){
hekeus@6 271 for (int i=0; i<numVoices;i++){
samer@16 272 voices[i]->highlight = voices[i]->isInVoice(x,y);
hekeus@6 273 }
hekeus@6 274 }
hekeus@6 275
hekeus@6 276 void melodyTriangle::mousePressed(int x, int y, int button){
hekeus@6 277
hekeus@6 278 for (int i=0; i<numVoices;i++){
samer@16 279 if (voices[i]->isInVoice(x,y)){
hekeus@6 280 voiceGrabbed=i;
hekeus@6 281 //printf("grabbed %i",voiceGrabbed);
hekeus@6 282 }else{
hekeus@6 283 //printf("didnt grab %i",i);
hekeus@6 284 }
hekeus@6 285 }
hekeus@6 286 }
hekeus@6 287
samer@22 288 void melodyTriangle::mouseReleased(int x, int y, int button){
samer@22 289 voiceGrabbed=-1;
hekeus@6 290 }
hekeus@6 291
hekeus@6 292 //--------------------------------------------------------------
samer@22 293
hekeus@6 294 void melodyTriangle::windowResized(int w, int h){
samer@22 295 fitTriangleIn(w,h);
samer@22 296 sendCalibrate();
samer@22 297 }
hekeus@6 298
samer@22 299
samer@22 300 // OSC Message handling -----------------------------------------
samer@22 301
samer@22 302 void melodyTriangle::handleMessage(ofxOscMessage &m) {
samer@22 303 string msg_path=m.getAddress();
samer@22 304
samer@22 305 if (msg_path=="/notify") {
samer@22 306 int id=m.getArgAsInt32(0)-1;
samer@22 307 string st=m.getArgAsString(1);
samer@22 308
samer@22 309 if (id>=0 && id<numVoices) {
samer@22 310 Voice *v=voices[id];
samer@22 311
samer@22 312 if (st=="received") v->status=Voice::clear;
samer@22 313 else if (st=="pending") v->status=Voice::pending;
samer@22 314 else if (st=="requested") v->status=Voice::waiting;
samer@22 315 else cout << "** unrecognised voice status: " << st << ".\n";
samer@22 316 } else {
samer@22 317 cout << "** voice id "<<id<<" out of range.\n";
samer@22 318 }
samer@22 319 } else if (msg_path=="/display") {
samer@22 320 display_msg=m.getArgAsString(0);
samer@22 321 display_frames=m.getArgAsInt32(1);
samer@22 322 if (display_frames<0) display_frames=0;
samer@22 323 } else {
samer@22 324 string msg_string;
samer@22 325 msg_string = m.getAddress();
samer@22 326 msg_string += ": ";
samer@22 327 for ( int i=0; i<m.getNumArgs(); i++ )
samer@22 328 {
samer@22 329 // get the argument type
samer@22 330 msg_string += m.getArgTypeName( i );
samer@22 331 msg_string += ":";
samer@22 332 // display the argument - make sure we get the right type
samer@22 333 if( m.getArgType( i ) == OFXOSC_TYPE_INT32 )
samer@22 334 msg_string += ofToString( m.getArgAsInt32( i ) );
samer@22 335 else if( m.getArgType( i ) == OFXOSC_TYPE_FLOAT )
samer@22 336 msg_string += ofToString( m.getArgAsFloat( i ) );
samer@22 337 else if( m.getArgType( i ) == OFXOSC_TYPE_STRING )
samer@22 338 msg_string += m.getArgAsString( i );
samer@22 339 else
samer@22 340 msg_string += "unknown";
samer@22 341 }
samer@22 342 cout<< msg_string << "\n";
samer@22 343 }
hekeus@6 344 }
samer@22 345
samer@22 346 // OSC Message sending -----------------------------------------
samer@22 347
samer@22 348 void melodyTriangle::sendPosition(Voice v){
samer@22 349
samer@22 350 ofxOscMessage m;
samer@22 351 ///track id x y left right top bottom area
samer@22 352 m.setAddress( "/track2d" );
samer@22 353 m.addIntArg( v.id );
samer@22 354 m.addIntArg( v.posx );
samer@22 355 m.addIntArg( v.posy );
samer@22 356 sender.sendMessage( m );
samer@22 357 printf("sent - /track2d %i %i %i\n",v.id,v.posx,v.posy);
samer@22 358
samer@22 359 }
samer@22 360 void melodyTriangle::sendCalibrate(){
samer@22 361 ofxOscMessage m;
samer@22 362 m.setAddress( "/calibrate" );
samer@22 363 m.addIntArg( x1 );
samer@22 364 m.addIntArg( y1 );
samer@22 365 m.addIntArg( x2 );
samer@22 366 m.addIntArg( y2 );
samer@22 367 m.addIntArg( x3 );
samer@22 368 m.addIntArg( y3 );
samer@22 369 sender.sendMessage( m );
samer@22 370 printf("sent /calibrate %i %i %i %i %i %i\n",x1,y1,x2,y2,x3,y3);
samer@22 371 }
samer@22 372
samer@22 373 void melodyTriangle::sendReplyTo(){
samer@22 374 ofxOscMessage m;
samer@22 375 m.setAddress( "/reply_to" );
samer@22 376 m.addIntArg( receivePort );
samer@22 377 sender.sendMessage( m );
samer@22 378 printf("sent /reply_to %i\n",receivePort);
samer@22 379 }
samer@22 380
samer@22 381 void melodyTriangle::sendPeriod(int id, int num, int den){
samer@22 382 ofxOscMessage m;
samer@22 383 m.setAddress("/period");
samer@22 384 m.addIntArg(id);
samer@22 385 m.addIntArg(num);
samer@22 386 m.addIntArg(den);
samer@22 387 sender.sendMessage(m);
samer@22 388 printf("sent /period %i %i %i\n",id,num,den);
samer@22 389 }
samer@22 390
samer@22 391 void melodyTriangle::sendShift(int id, int num, int den){
samer@22 392 ofxOscMessage m;
samer@22 393 m.setAddress("/shift");
samer@22 394 m.addIntArg(id);
samer@22 395 m.addIntArg(num);
samer@22 396 m.addIntArg(den);
samer@22 397 sender.sendMessage(m);
samer@22 398 printf("sent /shift %i %i %i\n",id,num,den);
samer@22 399 }
samer@22 400
samer@22 401 void melodyTriangle::sendOctave(int id, int oct){
samer@22 402 ofxOscMessage m;
samer@22 403 m.setAddress("/octave");
samer@22 404 m.addIntArg(id);
samer@22 405 m.addIntArg(oct);
samer@22 406 sender.sendMessage(m);
samer@22 407 printf("sent /octave %i %i\n",id,oct);
samer@22 408 }
samer@22 409
samer@22 410 void melodyTriangle::sendAmplitude(int id, float amp){
samer@22 411 ofxOscMessage m;
samer@22 412 m.setAddress("/amplitude");
samer@22 413 m.addIntArg(id);
samer@22 414 m.addFloatArg(amp);
samer@22 415 sender.sendMessage(m);
samer@22 416 printf("sent /amplitude %i %1.3f\n",id,amp);
samer@22 417 }
samer@22 418
samer@22 419
samer@22 420 void melodyTriangle::fitTriangleIn(int width, int height) {
samer@22 421 int triHeight = height*0.75;
samer@22 422 int triHalfWidth = triHeight/sqrt(3);
samer@22 423
samer@22 424 x1=width/2;
samer@22 425 x2=x1-triHalfWidth;
samer@22 426 x3=x1+triHalfWidth;
samer@22 427 y1=(height-triHeight)/2;
samer@22 428 y2=y3=height - (height-triHeight)/2;
samer@22 429
samer@22 430 // used for clipping
samer@22 431 DX13=x3-x1; DY13=y3-y1;
samer@22 432 SQLEN13=DX13*DX13+DY13*DY13;
samer@22 433 }