Mercurial > hg > screen-ui
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 |