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