Mercurial > hg > screen-ui
diff src/melodyTriangle.cpp @ 23:460c05dd74d0
Various enhancements and code refactorings:
* added some compiler warnings.
* text display is centred and with settable TrueType font
* removed highlight member from Voice state - value is derived from other data
and passed to Voice::draw()
* Changed voice radius from member to defined constant
* default number of voices is now 4
* adjusted some colours and buffer zone width
* new keyboard commands: reset, quit.
* when keyboard disabled, keys are now passed to server via OSC
* added handlers for various new OSC messages:
- fullscreen, reset, quit, keyboard enable
- notify (voice state) : several sub-messages
* call reset and calibrate on window resize (fits triangle to window)
author | samer |
---|---|
date | Sat, 04 Feb 2012 23:14:38 +0000 |
parents | 4dcc4312b5fa |
children | f4ebb87adec1 |
line wrap: on
line diff
--- a/src/melodyTriangle.cpp Thu Feb 02 18:17:24 2012 +0000 +++ b/src/melodyTriangle.cpp Sat Feb 04 23:14:38 2012 +0000 @@ -1,30 +1,20 @@ #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 - - - */ +#define BUFFER_ZONE 64 // have to drag this far to snap out of triange. 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) + display_msg(""), display_frames(0) { - printf("in constructor: %s %i %i %i %i %i\n",host,port,numVoices,enableKeys,voiceIdOffset,receivePort); + 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); + display_font.loadFont("/System/Library/Fonts/HelveticaLight.ttf",24); } melodyTriangle::~melodyTriangle() { @@ -37,22 +27,17 @@ 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); + ofSetFrameRate(40); // caps framerate if vertical sync is off. 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(); + sendReplyTo(); - for (int i=0;i<numVoices;i++) voices[i]->setPos(x2+voices[i]->radius+i*30,48); voiceGrabbed=-1; } @@ -80,17 +65,11 @@ // 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); + sendDeath(vg->id); vg->posx=mouseX; vg->posy=mouseY; vg->inTriangle=false; - vg->status=Voice::clear; + vg->status=Voice::pending; } else { // otherwise, we move to clipped point constrained=true; @@ -121,7 +100,7 @@ } if (vg->inTriangle){ - sendPosition(*vg); + sendPosition(vg); vg->status=Voice::moved; if (sendStart && vg->isActive){ ofxOscMessage m; @@ -141,24 +120,26 @@ //-------------------------------------------------------------- void melodyTriangle::draw(){ ofSetLineWidth(2); - ofSetColor(80,80,80); + ofSetColor(60,60,60); ofFill(); ofTriangle(x1, y1, x2, y2, x3, y3); - if (constrained) ofSetColor(255,96,96); // draw smooth edge, brighter if a token is constrained + if (constrained) ofSetColor(255,96,96); ofNoFill(); ofTriangle(x1, y1, x2, y2, x3, y3); for (int i=0; i<numVoices; i++){ - (*voices[i]).draw(); + voices[i]->draw(voices[i]->isInVoice(mouseX,mouseY)); } // display message if any - if (display_frames>0) { + if (display_frames!=0) { + ofRectangle bbox=display_font.getStringBoundingBox(display_msg,0,0); ofSetColor(220,220,220); - display_font.drawString(display_msg,x2,y1+32); - display_frames--; + display_font.drawString(display_msg, + (ofGetWidth()-bbox.width)/2, (ofGetHeight()-bbox.height)/2); + if (display_frames>0) display_frames--; } } @@ -202,7 +183,7 @@ //- Keyboard ---------------------------------------------------------- void melodyTriangle::keyReleased(int key){} -void melodyTriangle::keyPressed (int key){ +void melodyTriangle::keyPressed(int key){ //printf("key %i",key); if (enableKeys){ switch (key) { @@ -214,74 +195,69 @@ break; } - case '1': - case '2': - case '3': - case '4': { + 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; } - break; case 'c': sendReplyTo(); sendCalibrate(); break; - case 'f': ofToggleFullscreen(); break; + case 'F': ofToggleFullscreen(); break; + case 'R': reset(); break; + case 'Q': ofAppGlutWindow::exitApp(); - 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); - } - } - } - } + default: // otherwise, send key to all voices under mouse + for (int i=0; i<numVoices; i++) + if (voices[i]->isInVoice(mouseX,mouseY)) + voiceKeypress(voices[i],key); } + } else { + ofxOscMessage m; + m.setAddress( "/key" ); + m.addIntArg(key); + sender.sendMessage(m); + printf("sent /key %d\n", key); + } +} + +void melodyTriangle::voiceKeypress(Voice *v, int key) { + 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 ){ +void melodyTriangle::mouseMoved(int x, int y ){} +void melodyTriangle::mousePressed(int x, int y, int button){ 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); - } + if (voices[i]->isInVoice(x,y)) voiceGrabbed=i; } } @@ -294,67 +270,97 @@ void melodyTriangle::windowResized(int w, int h){ fitTriangleIn(w,h); sendCalibrate(); + reset(); } +void melodyTriangle::reset() { + voiceGrabbed=-1; + for (int i=0;i<numVoices;i++) { + Voice *v=voices[i]; + v->posx=x2+RADIUS+(numVoices-1-i)*36; + v->posy=48; + v->status=Voice::pending; + if (v->inTriangle) { + sendDeath(voices[i]->id); + v->inTriangle=false; + } + } +} // OSC Message handling ----------------------------------------- +Voice *melodyTriangle::get_voice(int id) throw(bad_voice_id) { + if (id<1 || id>numVoices) throw bad_voice_id(id); + return voices[id-1]; +} + 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"; + + try { + if (msg_path.compare(0,8,"/notify/")==0) { + Voice *v=get_voice(m.getArgAsInt32(0)); + if (msg_path=="/notify/status") { + v->status=Voice::stringToStatus(m.getArgAsString(1)); + } else if (msg_path=="/notify/position") { + int x=(int)m.getArgAsFloat(1); + int y=(int)m.getArgAsFloat(2); + v->posx=x; + v->posy=y; + v->inTriangle=!clipToTriangle(&x,&y); + if (voiceGrabbed==v->id) voiceGrabbed=-1; + } else if (msg_path=="/notify/running") { + v->isActive = m.getArgAsInt32(1) ? true : false; + } else if (msg_path=="/notify/params") { + v->octave = m.getArgAsInt32(1); + v->amplitude = m.getArgAsFloat(2); + } + } else if (msg_path=="/display") { + display_msg=m.getArgAsString(0); + display_frames=m.getArgAsInt32(1); + } else if (msg_path=="/font") { + display_font.loadFont(m.getArgAsString(0),m.getArgAsInt32(1)); + } else if (msg_path=="/keyboard") { enableKeys=m.getArgAsInt32(0); } + else if (msg_path=="/reset") { reset(); } + else if (msg_path=="/fullscreen") { ofSetFullscreen(m.getArgAsInt32(0)); } + else if (msg_path=="/quit") { ofAppGlutWindow::exitApp(); } + else { + cout << m.getAddress(); + for (int i=0; i<m.getNumArgs(); i++) { + cout << " " << m.getArgTypeName(i) << ":"; + switch (m.getArgType(i)) { + case OFXOSC_TYPE_INT32: cout << m.getArgAsInt32(i); + case OFXOSC_TYPE_FLOAT: cout << m.getArgAsFloat(i); + case OFXOSC_TYPE_STRING: cout << m.getArgAsString(i); + default: cout << "unknown"; + } + } + cout<< "\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"; + } catch (std::exception &ex) { + cout << "** Error processing OSC message: " << ex.what() << "\n"; } } // OSC Message sending ----------------------------------------- -void melodyTriangle::sendPosition(Voice v){ +void melodyTriangle::sendDeath(int id) { + ofxOscMessage m; + m.setAddress( "/death" ); + m.addIntArg( id ); + sender.sendMessage( m ); +} + +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 ); + 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); + printf("sent - /track2d %i %i %i\n",v->id,v->posx,v->posy); } void melodyTriangle::sendCalibrate(){ @@ -431,3 +437,10 @@ DX13=x3-x1; DY13=y3-y1; SQLEN13=DX13*DX13+DY13*DY13; } + +const char *melodyTriangle::bad_voice_id::what() const throw() { + std::stringstream out; + printf("bad_voice_id(%d).\n",id); + out << "Voice id " << id <<" out of range."; + return out.str().c_str(); +}