Mercurial > hg > screen-ui
view 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 |
line wrap: on
line source
#include "melodyTriangle.h" #include <GLUT/GLUT.h> #define BUFFER_ZONE 50 // 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): numVoices(numVoices), enableKeys(enableKeys), receivePort(receivePort), display_msg(""), display_frames(0) { printf("in constructor: %s %i %i %i %i %i\n",host,port,numVoices,enableKeys,voiceIdOffset,receivePort); for (int i=0;i<numVoices;i++) voices[i]=new Voice(i+1+voiceIdOffset); sender.setup( host,port ); receiver.setup( receivePort ); display_font.loadFont("/System/Library/Fonts/HelveticaLight.ttf",32); } melodyTriangle::~melodyTriangle() { printf("Deleting voice objects...\n"); for (int i=0;i<numVoices;i++) delete voices[i]; } //-------------------------------------------------------------- void melodyTriangle::setup(){ ofSetCircleResolution(64); 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(); sendReplyTo(); // 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 fitTriangleIn(ofGetWidth(),ofGetHeight()); sendCalibrate(); for (int i=0;i<numVoices;i++) voices[i]->setPos(x2+voices[i]->radius+i*30,48); voiceGrabbed=-1; } //-------------------------------------------------------------- void melodyTriangle::update(){ bool sendStart=false; while( receiver.hasWaitingMessages() ) { // get the next message ofxOscMessage m; receiver.getNextMessage( &m ); handleMessage(m); } constrained=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); } } } }; } //-------------------------------------------------------------- void melodyTriangle::draw(){ ofSetLineWidth(2); ofSetColor(80,80,80); 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(); } // display message if any if (display_frames>0) { ofSetColor(220,220,220); display_font.drawString(display_msg,x2,y1+32); display_frames--; } } 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; } //- Keyboard ---------------------------------------------------------- void melodyTriangle::keyReleased(int key){} 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': sendReplyTo(); sendCalibrate(); break; case 'f': ofToggleFullscreen(); 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); } } } } } } } //- Mouse ------------------------------------------------------ void melodyTriangle::mouseDragged(int x, int y, int button){} void melodyTriangle::mouseMoved(int x, int y ){ for (int i=0; i<numVoices;i++){ voices[i]->highlight = voices[i]->isInVoice(x,y); } } 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){ voiceGrabbed=-1; } //-------------------------------------------------------------- void melodyTriangle::windowResized(int w, int h){ fitTriangleIn(w,h); sendCalibrate(); } // OSC Message handling ----------------------------------------- void melodyTriangle::handleMessage(ofxOscMessage &m) { string msg_path=m.getAddress(); if (msg_path=="/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 if (msg_path=="/display") { display_msg=m.getArgAsString(0); display_frames=m.getArgAsInt32(1); if (display_frames<0) display_frames=0; } 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"; } } // OSC Message sending ----------------------------------------- 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::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::sendReplyTo(){ ofxOscMessage m; m.setAddress( "/reply_to" ); m.addIntArg( receivePort ); sender.sendMessage( m ); printf("sent /reply_to %i\n",receivePort); } 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::fitTriangleIn(int width, int height) { int triHeight = height*0.75; int triHalfWidth = triHeight/sqrt(3); x1=width/2; x2=x1-triHalfWidth; x3=x1+triHalfWidth; y1=(height-triHeight)/2; y2=y3=height - (height-triHeight)/2; // used for clipping DX13=x3-x1; DY13=y3-y1; SQLEN13=DX13*DX13+DY13*DY13; }