comparison src/melodyTriangle.cpp @ 25:f4ebb87adec1

Added code to keep track of true position of voices in information space; Two voice drawing methods display both true position target position while dragging; string to Voice::status code no longer required; refactored OSC message sending code; added keys to control subdivision ratio for period and shift controls.
author samer
date Sun, 05 Feb 2012 18:13:30 +0000
parents 460c05dd74d0
children 10afc9afb79d
comparison
equal deleted inserted replaced
24:328822cd308c 25:f4ebb87adec1
1 #include "melodyTriangle.h" 1 #include "melodyTriangle.h"
2 #include <GLUT/GLUT.h> 2 #include <GLUT/GLUT.h>
3 3
4 #define BUFFER_ZONE 64 // have to drag this far to snap out of triange. 4 #define BUFFER_ZONE 64 // have to drag this far to snap out of triange.
5
6 static int tempi[]={20,30,45,60,90,120,150,180};
5 7
6 melodyTriangle::melodyTriangle(const char *host, int port, int numVoices, 8 melodyTriangle::melodyTriangle(const char *host, int port, int numVoices,
7 bool enableKeys,int voiceIdOffset,int receivePort): 9 bool enableKeys,int voiceIdOffset,int receivePort):
8 numVoices(numVoices), enableKeys(enableKeys), receivePort(receivePort), 10 numVoices(numVoices), enableKeys(enableKeys), receivePort(receivePort),
9 display_msg(""), display_frames(0) 11 display_msg(""), display_frames(0), ratio(2), tempoIndex(4)
10 { 12 {
11 printf("in constructor: %s %i %i %i %i %i\n", 13 printf("in constructor: %s %i %i %i %i %i\n",
12 host,port,numVoices,enableKeys,voiceIdOffset,receivePort); 14 host,port,numVoices,enableKeys,voiceIdOffset,receivePort);
13 for (int i=0;i<numVoices;i++) voices[i]=new Voice(i+1+voiceIdOffset); 15 for (int i=0;i<numVoices;i++) voices[i]=new Voice(i+1+voiceIdOffset);
14 16
33 // Set up triange coordinates. 35 // Set up triange coordinates.
34 // NB. whatever happens here, the triangle must be 36 // NB. whatever happens here, the triangle must be
35 // isosceles and left-right symmetric around x=x1. 37 // isosceles and left-right symmetric around x=x1.
36 // Otherwise the clipping won't work 38 // Otherwise the clipping won't work
37 fitTriangleIn(ofGetWidth(),ofGetHeight()); 39 fitTriangleIn(ofGetWidth(),ofGetHeight());
40 send("/tempo",tempi[tempoIndex]);
38 sendCalibrate(); 41 sendCalibrate();
39 sendReplyTo(); 42 sendReplyTo();
40 43
41 voiceGrabbed=-1; 44 voiceGrabbed=NULL;
42 } 45 }
43 46
44 //-------------------------------------------------------------- 47 //--------------------------------------------------------------
45 void melodyTriangle::update(){ 48 void melodyTriangle::update(){
46 bool sendStart=false; 49 bool sendStart=false;
51 receiver.getNextMessage( &m ); 54 receiver.getNextMessage( &m );
52 handleMessage(m); 55 handleMessage(m);
53 } 56 }
54 57
55 constrained=false; 58 constrained=false;
56 if (voiceGrabbed!=-1){ 59 if (voiceGrabbed!=NULL){
57 Voice *vg=voices[voiceGrabbed]; 60 Voice *vg=voiceGrabbed;
58 if (mouseX!=vg->posx || mouseY!=vg->posy){ 61 if (mouseX!=vg->posx || mouseY!=vg->posy){
59 int clipx=mouseX, clipy=mouseY; 62 int clipx=mouseX, clipy=mouseY;
60 bool clipped=clipToTriangle(&clipx,&clipy); 63 bool clipped=clipToTriangle(&clipx,&clipy);
61 64
62 if (vg->inTriangle) { 65 if (vg->inTriangle) {
63 66
64 if (clipped) { 67 if (clipped) {
65 // check how far we clipped 68 // check how far we clipped
66 if (ofDist(clipx, clipy, mouseX, mouseY) > BUFFER_ZONE) { 69 if (ofDist(clipx, clipy, mouseX, mouseY) > BUFFER_ZONE) {
67 // if far enough, we pop out of triangle and send 70 // if far enough, we pop out of triangle and send
68 sendDeath(vg->id); 71 send("/death",vg->id);
69 vg->posx=mouseX; 72 vg->posx=mouseX;
70 vg->posy=mouseY; 73 vg->posy=mouseY;
71 vg->inTriangle=false; 74 vg->inTriangle=false;
72 vg->status=Voice::pending; 75 vg->status=Voice::pending;
73 } else { 76 } else {
82 } 85 }
83 } else { // token was outside triangle 86 } else { // token was outside triangle
84 vg->posx=mouseX; 87 vg->posx=mouseX;
85 vg->posy=mouseY; 88 vg->posy=mouseY;
86 if (!clipped){ // ie mouse now in triangle 89 if (!clipped){ // ie mouse now in triangle
87 //birth id 90 send("/birth",vg->id);
88
89 ofxOscMessage m;
90 m.setAddress( "/birth" );
91 m.addIntArg( vg->id );
92 sender.sendMessage( m );
93 91
94 printf("sent /birth %i \n",vg->id); 92 printf("sent /birth %i \n",vg->id);
95 sendOctave(vg->id,vg->octave); 93 sendOctave(vg->id,vg->octave);
96 sendAmplitude(vg->id,vg->amplitude); 94 sendAmplitude(vg->id,vg->amplitude);
97 sendStart=true; 95 sendStart=true;
98 vg->inTriangle=true; 96 vg->inTriangle=true;
97 vg->truex=vg->truey=-1; // ie not known yet.
99 } 98 }
100 } 99 }
101 100
102 if (vg->inTriangle){ 101 if (vg->inTriangle){
103 sendPosition(vg); 102 sendPosition(vg);
104 vg->status=Voice::moved; 103 vg->status=Voice::moved;
105 if (sendStart && vg->isActive){ 104 if (sendStart && vg->isActive) send("/start",vg->id);
106 ofxOscMessage m;
107 ///track id x y left right top bottom area
108 m.setAddress( "/start" );
109 m.addIntArg( vg->id );
110 sender.sendMessage( m );
111 printf("sent /start %i \n",vg->id);
112 }
113 } 105 }
114 } 106 }
115 }; 107 };
116 } 108 }
117 109
127 // draw smooth edge, brighter if a token is constrained 119 // draw smooth edge, brighter if a token is constrained
128 if (constrained) ofSetColor(255,96,96); 120 if (constrained) ofSetColor(255,96,96);
129 ofNoFill(); 121 ofNoFill();
130 ofTriangle(x1, y1, x2, y2, x3, y3); 122 ofTriangle(x1, y1, x2, y2, x3, y3);
131 123
132 for (int i=0; i<numVoices; i++){ 124 for (int i=numVoices-1; i>=0; i--){
133 voices[i]->draw(voices[i]->isInVoice(mouseX,mouseY)); 125 voices[i]->draw(voices[i]->isInVoice(mouseX,mouseY));
134 } 126 }
135 127
136 // display message if any 128 // display message if any
137 if (display_frames!=0) { 129 if (display_frames!=0) {
138 ofRectangle bbox=display_font.getStringBoundingBox(display_msg,0,0); 130 ofRectangle bbox=display_font.getStringBoundingBox(display_msg,0,0);
139 ofSetColor(220,220,220); 131 ofSetColor(220,220,220);
140 display_font.drawString(display_msg, 132 display_font.drawString(display_msg,
141 (ofGetWidth()-bbox.width)/2, (ofGetHeight()-bbox.height)/2); 133 (ofGetWidth()-bbox.width)/2, (ofGetHeight()-bbox.height)/2);
142 if (display_frames>0) display_frames--; 134 if (display_frames>0) display_frames--;
135 }
136 if (ratio!=2) {
137 ofSetColor(160,160,160);
138 display_font.drawString(ofToString(ratio),16,ofGetHeight()-16);
143 } 139 }
144 } 140 }
145 141
146 bool melodyTriangle::clipToTriangle(int *x, int *y) { 142 bool melodyTriangle::clipToTriangle(int *x, int *y) {
147 bool clipped; 143 bool clipped;
180 176
181 177
182 178
183 //- Keyboard ---------------------------------------------------------- 179 //- Keyboard ----------------------------------------------------------
184 180
185 void melodyTriangle::keyReleased(int key){} 181 void melodyTriangle::keyReleased(int key){
182 if (enableKeys && key>='2' && key<='9') {
183 ratio=2;
184 }
185 }
186 void melodyTriangle::keyPressed(int key){ 186 void melodyTriangle::keyPressed(int key){
187 //printf("key %i",key);
188 if (enableKeys){ 187 if (enableKeys){
189 switch (key) { 188 if (key>='2' && key<='9') {
190 case ' ': { 189 ratio=key-'0';
191 ofxOscMessage m; 190 } else {
192 m.setAddress( "/marker" ); 191 printf("got key: %d.\n",key);
193 sender.sendMessage(m); 192 switch (key) {
194 printf("sent /marker\n"); 193
195 break; 194 case '{':
196 } 195 if (tempoIndex>0) tempoIndex--;
197 196 send("/tempo",tempi[tempoIndex]);
198 case '1': case '2': 197 break;
199 case '3': case '4': { 198 case '}':
200 int tempo=30 + 30*(key-'1'); 199 if (tempoIndex<7) tempoIndex++;
201 ofxOscMessage m; 200 send("/tempo",tempi[tempoIndex]);
202 m.setAddress( "/tempo" ); 201 break;
203 m.addIntArg(tempo); 202
204 sender.sendMessage( m ); 203 case ' ': send("/marker"); break;
205 printf("sent /tempo %d\n",tempo); 204 case 'S': send("/save"); break;
206 break; 205 case 'C': sendReplyTo(); sendCalibrate(); break;
207 } 206 case 'F': ofToggleFullscreen(); break;
208 207 case 'R': reset(); break;
209 case 'c': sendReplyTo(); sendCalibrate(); break; 208 case 'Q': ofAppGlutWindow::exitApp();
210 case 'F': ofToggleFullscreen(); break; 209
211 case 'R': reset(); break; 210 default: // otherwise, send key to all voices under mouse
212 case 'Q': ofAppGlutWindow::exitApp(); 211 for (int i=0; i<numVoices; i++)
213 212 if (voices[i]->isInVoice(mouseX,mouseY))
214 default: // otherwise, send key to all voices under mouse 213 voiceKeypress(voices[i],key);
215 for (int i=0; i<numVoices; i++) 214 }
216 if (voices[i]->isInVoice(mouseX,mouseY)) 215 }
217 voiceKeypress(voices[i],key); 216 } else send("/key",key);
218 }
219 } else {
220 ofxOscMessage m;
221 m.setAddress( "/key" );
222 m.addIntArg(key);
223 sender.sendMessage(m);
224 printf("sent /key %d\n", key);
225 }
226 } 217 }
227 218
228 void melodyTriangle::voiceKeypress(Voice *v, int key) { 219 void melodyTriangle::voiceKeypress(Voice *v, int key) {
229 switch (key) { 220 switch (key) {
230 case 'a': { 221 case 'a':
231 ofxOscMessage m; 222 send(v->isActive ? "/stop" : "/start", v->id);
232 const char *addr = v->isActive ? "/stop" : "/start";
233 v->isActive=!v->isActive; 223 v->isActive=!v->isActive;
234 m.setAddress(addr);
235 m.addIntArg(v->id );
236 sender.sendMessage( m );
237 printf("sent %s %i \n",addr,v->id);
238 break; 224 break;
239 } 225 case OF_KEY_LEFT: sendShift(v->id,-1,ratio); break;
240 case OF_KEY_LEFT: sendShift(v->id,-1,2); break; 226 case OF_KEY_RIGHT: sendShift(v->id,1,ratio); break;
241 case OF_KEY_RIGHT: sendShift(v->id,1,2); break; 227 case OF_KEY_UP: sendPeriod(v->id,1,ratio); break;
242 case OF_KEY_UP: sendPeriod(v->id,1,2); break; 228 case OF_KEY_DOWN: sendPeriod(v->id,ratio,1); break;
243 case OF_KEY_DOWN: sendPeriod(v->id,2,1); break; 229 case ']': sendOctave(v->id, ++v->octave); break;
244 case '.': sendPeriod(v->id,1,3); break; 230 case '[': sendOctave(v->id, --v->octave); break;
245 case ',': sendPeriod(v->id,3,1); break;
246 case '+': sendOctave(v->id, ++v->octave); break;
247 case '-': sendOctave(v->id, --v->octave); break;
248 case '*': sendAmplitude(v->id, v->louder()); break; 231 case '*': sendAmplitude(v->id, v->louder()); break;
249 case '/': sendAmplitude(v->id, v->quieter()); break; 232 case '/': sendAmplitude(v->id, v->quieter()); break;
233 case 'c': send("/change",v->id); v->status=Voice::pending; break;
250 default: printf("unrecognised key: %d.\n",key); 234 default: printf("unrecognised key: %d.\n",key);
251 } 235 }
252 } 236 }
253 237
254 //- Mouse ------------------------------------------------------ 238 //- Mouse ------------------------------------------------------
255 239
256 void melodyTriangle::mouseDragged(int x, int y, int button){} 240 void melodyTriangle::mouseDragged(int x, int y, int button){}
257 void melodyTriangle::mouseMoved(int x, int y ){} 241 void melodyTriangle::mouseMoved(int x, int y ){}
258 void melodyTriangle::mousePressed(int x, int y, int button){ 242 void melodyTriangle::mousePressed(int x, int y, int button){
243 // pick up first token under mouse
259 for (int i=0; i<numVoices;i++){ 244 for (int i=0; i<numVoices;i++){
260 if (voices[i]->isInVoice(x,y)) voiceGrabbed=i; 245 if (voices[i]->isInVoice(x,y)) {
246 voiceGrabbed=voices[i];
247 break;
248 }
261 } 249 }
262 } 250 }
263 251
264 void melodyTriangle::mouseReleased(int x, int y, int button){ 252 void melodyTriangle::mouseReleased(int x, int y, int button){
265 voiceGrabbed=-1; 253 if (voiceGrabbed!=NULL) {
254 Voice *v=voiceGrabbed;
255 if (v->status==Voice::clear) {
256 v->posx=v->truex;
257 v->posy=v->truey;
258 v->truex=v->truey=-1;
259 }
260 voiceGrabbed=NULL;
261 }
266 } 262 }
267 263
268 //-------------------------------------------------------------- 264 //--------------------------------------------------------------
269 265
270 void melodyTriangle::windowResized(int w, int h){ 266 void melodyTriangle::windowResized(int w, int h){
272 sendCalibrate(); 268 sendCalibrate();
273 reset(); 269 reset();
274 } 270 }
275 271
276 void melodyTriangle::reset() { 272 void melodyTriangle::reset() {
277 voiceGrabbed=-1; 273 voiceGrabbed=NULL;
278 for (int i=0;i<numVoices;i++) { 274 for (int i=0;i<numVoices;i++) {
279 Voice *v=voices[i]; 275 Voice *v=voices[i];
280 v->posx=x2+RADIUS+(numVoices-1-i)*36; 276 v->posx=x2+RADIUS+(numVoices-1-i)*36;
281 v->posy=48; 277 v->posy=48;
282 v->status=Voice::pending; 278 v->status=Voice::pending;
279 v->isActive=true;
283 if (v->inTriangle) { 280 if (v->inTriangle) {
284 sendDeath(voices[i]->id); 281 send("/death",voices[i]->id);
285 v->inTriangle=false; 282 v->inTriangle=false;
286 } 283 }
287 } 284 }
288 } 285 }
289 286
297 void melodyTriangle::handleMessage(ofxOscMessage &m) { 294 void melodyTriangle::handleMessage(ofxOscMessage &m) {
298 string msg_path=m.getAddress(); 295 string msg_path=m.getAddress();
299 296
300 try { 297 try {
301 if (msg_path.compare(0,8,"/notify/")==0) { 298 if (msg_path.compare(0,8,"/notify/")==0) {
299 string msg=msg_path.substr(8);
302 Voice *v=get_voice(m.getArgAsInt32(0)); 300 Voice *v=get_voice(m.getArgAsInt32(0));
303 if (msg_path=="/notify/status") { 301
304 v->status=Voice::stringToStatus(m.getArgAsString(1)); 302 if (msg=="requested") v->status=Voice::waiting;
305 } else if (msg_path=="/notify/position") { 303 else if (msg=="pending") v->status=Voice::pending;
304 else if (msg=="received") {
305 float x=m.getArgAsFloat(1);
306 float y=m.getArgAsFloat(2);
307 v->status=Voice::clear;
308 if (voiceGrabbed==v) {
309 v->truex=x;
310 v->truey=y;
311 } else {
312 v->posx=x;
313 v->posy=y;
314 v->truex=v->truey=-1;
315 }
316 printf("True position of %d: %4.1f, %4.1f\n",v->id,v->truex,v->truey);
317 } else if (msg=="position") {
306 int x=(int)m.getArgAsFloat(1); 318 int x=(int)m.getArgAsFloat(1);
307 int y=(int)m.getArgAsFloat(2); 319 int y=(int)m.getArgAsFloat(2);
308 v->posx=x; 320 v->posx=x;
309 v->posy=y; 321 v->posy=y;
310 v->inTriangle=!clipToTriangle(&x,&y); 322 v->inTriangle=!clipToTriangle(&x,&y);
311 if (voiceGrabbed==v->id) voiceGrabbed=-1; 323 if (voiceGrabbed==v) voiceGrabbed=NULL;
312 } else if (msg_path=="/notify/running") { 324 } else if (msg=="running") {
313 v->isActive = m.getArgAsInt32(1) ? true : false; 325 v->isActive = m.getArgAsInt32(1) ? true : false;
314 } else if (msg_path=="/notify/params") { 326 } else if (msg=="params") {
315 v->octave = m.getArgAsInt32(1); 327 v->octave = m.getArgAsInt32(1);
316 v->amplitude = m.getArgAsFloat(2); 328 v->amplitude = m.getArgAsFloat(2);
317 } 329 }
318 } else if (msg_path=="/display") { 330 } else if (msg_path=="/display") {
319 display_msg=m.getArgAsString(0); 331 display_msg=m.getArgAsString(0);
342 } 354 }
343 } 355 }
344 356
345 // OSC Message sending ----------------------------------------- 357 // OSC Message sending -----------------------------------------
346 358
347 void melodyTriangle::sendDeath(int id) {
348 ofxOscMessage m;
349 m.setAddress( "/death" );
350 m.addIntArg( id );
351 sender.sendMessage( m );
352 }
353
354 void melodyTriangle::sendPosition(Voice *v){ 359 void melodyTriangle::sendPosition(Voice *v){
355 360
356 ofxOscMessage m; 361 ofxOscMessage m;
357 ///track id x y left right top bottom area 362 ///track id x y left right top bottom area
358 m.setAddress( "/track2d" ); 363 m.setAddress( "/track2d" );
359 m.addIntArg( v->id ); 364 m.addIntArg( v->id );
360 m.addIntArg( v->posx ); 365 m.addIntArg( v->posx );
361 m.addIntArg( v->posy ); 366 m.addIntArg( v->posy );
362 sender.sendMessage( m ); 367 sender.sendMessage( m );
363 printf("sent - /track2d %i %i %i\n",v->id,v->posx,v->posy); 368 // printf("sent - /track2d %i %i %i\n",v->id,v->posx,v->posy);
364
365 } 369 }
366 void melodyTriangle::sendCalibrate(){ 370 void melodyTriangle::sendCalibrate(){
367 ofxOscMessage m; 371 ofxOscMessage m;
368 m.setAddress( "/calibrate" ); 372 m.setAddress( "/calibrate" );
369 m.addIntArg( x1 ); 373 m.addIntArg( x1 );
420 m.addFloatArg(amp); 424 m.addFloatArg(amp);
421 sender.sendMessage(m); 425 sender.sendMessage(m);
422 printf("sent /amplitude %i %1.3f\n",id,amp); 426 printf("sent /amplitude %i %1.3f\n",id,amp);
423 } 427 }
424 428
429 void melodyTriangle::send(const char *addr, int a) {
430 ofxOscMessage m;
431 m.setAddress(addr);
432 m.addIntArg(a);
433 sender.sendMessage(m);
434 printf("sent %s %i\n",addr,a);
435 }
436
437 void melodyTriangle::send(const char *addr) {
438 ofxOscMessage m;
439 m.setAddress(addr);
440 sender.sendMessage(m);
441 printf("sent %s\n",addr);
442 }
425 443
426 void melodyTriangle::fitTriangleIn(int width, int height) { 444 void melodyTriangle::fitTriangleIn(int width, int height) {
427 int triHeight = height*0.75; 445 int triHeight = height*0.75;
428 int triHalfWidth = triHeight/sqrt(3); 446 int triHalfWidth = triHeight/sqrt(3);
429 447