hekeus@6
|
1 #include "melodyTriangle.h"
|
hekeus@6
|
2 #include <GLUT/GLUT.h>
|
hekeus@6
|
3
|
samer@23
|
4 #define BUFFER_ZONE 64 // have to drag this far to snap out of triange.
|
samer@32
|
5 #define NUM_TEMPI 9
|
samer@38
|
6 #define NUMEL(a) sizeof(a)/sizeof(a[0])
|
samer@22
|
7
|
samer@32
|
8 static int tempi[]={20,30,45,60,90,120,150,180,240};
|
samer@32
|
9
|
samer@37
|
10 static ofxOscBundle& operator<<(ofxOscBundle &bundle, ofxOscMessage msg) {
|
samer@37
|
11 bundle.addMessage(msg); return bundle;
|
samer@37
|
12 }
|
samer@37
|
13
|
samer@37
|
14 static ofxOscSender& operator<<(ofxOscSender &sender, ofxOscMessage msg) {
|
samer@37
|
15 sender.sendMessage(msg);
|
samer@37
|
16 return sender;
|
samer@37
|
17 }
|
samer@37
|
18
|
samer@37
|
19 static ofxOscSender& operator<<(ofxOscSender &sender, ofxOscBundle bundle) {
|
samer@37
|
20 sender.sendBundle(bundle);
|
samer@37
|
21 return sender;
|
samer@37
|
22 }
|
samer@37
|
23
|
samer@25
|
24
|
samer@22
|
25 melodyTriangle::melodyTriangle(const char *host, int port, int numVoices,
|
samer@22
|
26 bool enableKeys,int voiceIdOffset,int receivePort):
|
samer@31
|
27 numVoices(numVoices), receivePort(receivePort), snapTruePos(enableKeys),
|
samer@37
|
28 enableKeys(enableKeys), randInit(false),allowExit(true), ratio(2), tempoIndex(4),
|
samer@38
|
29 display_msg(""), display_frames(0), display_font(NULL)
|
samer@22
|
30 {
|
samer@22
|
31 for (int i=0;i<numVoices;i++) voices[i]=new Voice(i+1+voiceIdOffset);
|
samer@22
|
32
|
hekeus@6
|
33 sender.setup( host,port );
|
hekeus@8
|
34 receiver.setup( receivePort );
|
samer@38
|
35 main_font.loadFont("/System/Library/Fonts/LucidaGrande.ttc",24);
|
samer@38
|
36 help_font.loadFont("/System/Library/Fonts/Menlo.ttc",16);
|
samer@38
|
37 //help_font.loadFont("/System/Library/Fonts/Courier.dfont",16);
|
hekeus@6
|
38 }
|
hekeus@6
|
39
|
samer@22
|
40 melodyTriangle::~melodyTriangle() {
|
samer@22
|
41 printf("Deleting voice objects...\n");
|
samer@22
|
42 for (int i=0;i<numVoices;i++) delete voices[i];
|
samer@22
|
43 }
|
samer@22
|
44
|
hekeus@6
|
45 //--------------------------------------------------------------
|
hekeus@6
|
46 void melodyTriangle::setup(){
|
samer@22
|
47 ofSetCircleResolution(64);
|
hekeus@6
|
48 ofBackground(0,0,0);
|
hekeus@6
|
49 ofSetWindowTitle("Melody Triangle");
|
samer@23
|
50 ofSetFrameRate(40); // caps framerate if vertical sync is off.
|
samer@18
|
51 ofEnableSmoothing();
|
samer@18
|
52
|
samer@18
|
53 // Set up triange coordinates.
|
samer@18
|
54 // NB. whatever happens here, the triangle must be
|
samer@18
|
55 // isosceles and left-right symmetric around x=x1.
|
samer@18
|
56 // Otherwise the clipping won't work
|
samer@22
|
57 fitTriangleIn(ofGetWidth(),ofGetHeight());
|
samer@37
|
58
|
samer@37
|
59 ofxOscBundle bundle;
|
samer@37
|
60 sender << ( bundle
|
samer@37
|
61 << msg("/tempo",tempi[tempoIndex])
|
samer@37
|
62 << msgCalibrate()
|
samer@37
|
63 << msgReplyTo());
|
hekeus@6
|
64
|
samer@25
|
65 voiceGrabbed=NULL;
|
samer@12
|
66 }
|
samer@12
|
67
|
hekeus@6
|
68 //--------------------------------------------------------------
|
hekeus@6
|
69 void melodyTriangle::update(){
|
samer@22
|
70 bool sendStart=false;
|
samer@22
|
71
|
samer@22
|
72 while( receiver.hasWaitingMessages() ) {
|
hekeus@8
|
73 // get the next message
|
hekeus@8
|
74 ofxOscMessage m;
|
hekeus@8
|
75 receiver.getNextMessage( &m );
|
samer@22
|
76 handleMessage(m);
|
hekeus@8
|
77 }
|
samer@15
|
78
|
samer@22
|
79 constrained=false;
|
samer@25
|
80 if (voiceGrabbed!=NULL){
|
samer@25
|
81 Voice *vg=voiceGrabbed;
|
samer@14
|
82 if (mouseX!=vg->posx || mouseY!=vg->posy){
|
samer@15
|
83 int clipx=mouseX, clipy=mouseY;
|
samer@15
|
84 bool clipped=clipToTriangle(&clipx,&clipy);
|
samer@37
|
85 ofxOscBundle bundle;
|
samer@15
|
86
|
samer@15
|
87 if (vg->inTriangle) {
|
hekeus@6
|
88
|
samer@15
|
89 if (clipped) {
|
samer@15
|
90 // check how far we clipped
|
samer@30
|
91 if (ofDist(clipx, clipy, mouseX, mouseY)>BUFFER_ZONE && allowExit) {
|
samer@15
|
92 // if far enough, we pop out of triangle and send
|
samer@37
|
93 bundle << msg("/death",vg->id);
|
samer@37
|
94 sender << bundle;
|
samer@15
|
95 vg->posx=mouseX;
|
samer@15
|
96 vg->posy=mouseY;
|
samer@15
|
97 vg->inTriangle=false;
|
samer@23
|
98 vg->status=Voice::pending;
|
samer@15
|
99 } else {
|
samer@15
|
100 // otherwise, we move to clipped point
|
samer@15
|
101 constrained=true;
|
samer@15
|
102 vg->posx=clipx;
|
samer@15
|
103 vg->posy=clipy;
|
samer@15
|
104 }
|
samer@15
|
105 } else { // not clipped; normal move
|
samer@15
|
106 vg->posx=mouseX;
|
samer@15
|
107 vg->posy=mouseY;
|
samer@15
|
108 }
|
samer@15
|
109 } else { // token was outside triangle
|
samer@15
|
110 vg->posx=mouseX;
|
samer@15
|
111 vg->posy=mouseY;
|
samer@15
|
112 if (!clipped){ // ie mouse now in triangle
|
samer@37
|
113 bundle << msg("/birth",vg->id)
|
samer@37
|
114 << msgAmplitude(vg->id,vg->amplitude)
|
samer@37
|
115 << ( randInit
|
samer@37
|
116 ? msg("/randinit",vg->id)
|
samer@37
|
117 : msgOctave(vg->id,vg->octave)
|
samer@37
|
118 );
|
samer@15
|
119 sendStart=true;
|
samer@15
|
120 vg->inTriangle=true;
|
samer@25
|
121 vg->truex=vg->truey=-1; // ie not known yet.
|
hekeus@6
|
122 }
|
hekeus@6
|
123 }
|
hekeus@6
|
124
|
samer@14
|
125 if (vg->inTriangle){
|
samer@37
|
126 bundle << msgPosition(vg);
|
samer@18
|
127 vg->status=Voice::moved;
|
samer@37
|
128 if (sendStart && vg->isActive) bundle << msg("/start",vg->id);
|
samer@37
|
129 sender << bundle;
|
hekeus@6
|
130 }
|
hekeus@6
|
131 }
|
hekeus@6
|
132 };
|
samer@22
|
133 }
|
samer@10
|
134
|
samer@22
|
135
|
samer@22
|
136
|
samer@22
|
137 //--------------------------------------------------------------
|
samer@22
|
138 void melodyTriangle::draw(){
|
samer@11
|
139 ofSetLineWidth(2);
|
samer@23
|
140 ofSetColor(60,60,60);
|
samer@10
|
141 ofFill();
|
samer@10
|
142 ofTriangle(x1, y1, x2, y2, x3, y3);
|
samer@10
|
143
|
samer@10
|
144 // draw smooth edge, brighter if a token is constrained
|
samer@23
|
145 if (constrained) ofSetColor(255,96,96);
|
samer@10
|
146 ofNoFill();
|
samer@10
|
147 ofTriangle(x1, y1, x2, y2, x3, y3);
|
samer@10
|
148
|
samer@25
|
149 for (int i=numVoices-1; i>=0; i--){
|
samer@32
|
150 voices[i]->draw(enableKeys && voices[i]->isInVoice(mouseX,mouseY));
|
hekeus@6
|
151 }
|
hekeus@6
|
152
|
samer@22
|
153 // display message if any
|
samer@23
|
154 if (display_frames!=0) {
|
samer@38
|
155 ofRectangle bbox=display_font->getStringBoundingBox(display_msg,0,0);
|
samer@22
|
156 ofSetColor(220,220,220);
|
samer@38
|
157 display_font->drawString(display_msg,
|
samer@23
|
158 (ofGetWidth()-bbox.width)/2, (ofGetHeight()-bbox.height)/2);
|
samer@23
|
159 if (display_frames>0) display_frames--;
|
samer@22
|
160 }
|
samer@25
|
161 if (ratio!=2) {
|
samer@25
|
162 ofSetColor(160,160,160);
|
samer@38
|
163 display_font->drawString(ofToString(ratio),16,ofGetHeight()-16);
|
samer@25
|
164 }
|
hekeus@6
|
165 }
|
hekeus@6
|
166
|
samer@22
|
167 bool melodyTriangle::clipToTriangle(int *x, int *y) {
|
samer@22
|
168 bool clipped;
|
samer@22
|
169
|
samer@22
|
170 if (*y>y2) { // off the bottom
|
samer@22
|
171 clipped=true;
|
samer@22
|
172 *y=y2;
|
samer@22
|
173 if (*x<x2) *x=x2;
|
samer@22
|
174 else if (*x>x3) *x=x3;
|
samer@22
|
175 } else { // have to be a bit cleverer
|
samer@22
|
176 bool reflect=false;
|
samer@22
|
177 if (*x<x1) { // work in reflected coordinates
|
samer@22
|
178 reflect=true;
|
samer@22
|
179 *x=2*x1-*x;
|
samer@22
|
180 }
|
samer@22
|
181
|
samer@22
|
182 int dx=(*x-x1), dy=(*y-y1); // deltas from top
|
samer@22
|
183 if (dx*DY13 > dy*DX13) {
|
samer@22
|
184 // (x,y) must be somewhere right of triangle now
|
samer@22
|
185 clipped=true;
|
samer@22
|
186 int dp=dx*DX13 + dy*DY13;
|
samer@22
|
187 if (dp<0) { *x=x1; *y=y1; } // off the top
|
samer@22
|
188 else if (dp>SQLEN13) { *x=x3; *y=y3; } // off the bottom right
|
samer@22
|
189 else { // project onto right edge
|
samer@22
|
190 *x=x1+dp*DX13/SQLEN13;
|
samer@22
|
191 *y=y1+dp*DY13/SQLEN13;
|
samer@22
|
192 }
|
samer@22
|
193 } else {
|
samer@22
|
194 clipped=false;
|
samer@22
|
195 }
|
samer@22
|
196
|
samer@22
|
197 if (reflect) *x=2*x1 - *x; // reflect back if necessary
|
samer@22
|
198 }
|
samer@22
|
199 return clipped;
|
samer@22
|
200 }
|
samer@22
|
201
|
samer@22
|
202
|
samer@22
|
203
|
samer@22
|
204 //- Keyboard ----------------------------------------------------------
|
samer@22
|
205
|
samer@25
|
206 void melodyTriangle::keyReleased(int key){
|
samer@25
|
207 if (enableKeys && key>='2' && key<='9') {
|
samer@25
|
208 ratio=2;
|
samer@25
|
209 }
|
samer@25
|
210 }
|
samer@38
|
211
|
samer@38
|
212 struct command {
|
samer@38
|
213 const char *key;
|
samer@38
|
214 const char *desc;
|
samer@38
|
215 };
|
samer@38
|
216
|
samer@38
|
217 struct command voice_commands[] = {
|
samer@38
|
218 // { "←", "fractional delay" },
|
samer@38
|
219 // { "→", "fractional advance" },
|
samer@38
|
220 // { "↑", "multiply note rate" },
|
samer@38
|
221 // { "↓", "divide note rate" },
|
samer@38
|
222 { "[right]", "fractional delay" },
|
samer@38
|
223 { "[left]", "fractional advance" },
|
samer@38
|
224 { "[up]", "multiply note rate" },
|
samer@38
|
225 { "[down]", "divide note rate" },
|
samer@38
|
226 { "[", "transpose octave down" },
|
samer@38
|
227 { "]", "transpose octave up" },
|
samer@38
|
228 { "{", "quieter" },
|
samer@38
|
229 { "}", "louder" },
|
samer@38
|
230 { "c", "change to nearby pattern" },
|
samer@38
|
231 { "s", "shuffle notes" },
|
samer@38
|
232 { "h", "this help screen" },
|
samer@38
|
233 { "H", "global keys help screen" },
|
samer@38
|
234 };
|
samer@38
|
235
|
samer@38
|
236 struct command global_commands[] = {
|
samer@38
|
237 { "<", "reduce tempo" },
|
samer@38
|
238 { ">", "increase tempo" },
|
samer@38
|
239 { "I", "toggle randomise on birth" },
|
samer@38
|
240 { "S", "save current pattern" },
|
samer@38
|
241 { "C", "calibrate triangle" },
|
samer@38
|
242 { "F", "toggle full screen" },
|
samer@38
|
243 { "R", "reset token positions" },
|
samer@38
|
244 { "Q", "quit" },
|
samer@38
|
245 { "H", "this help screen" },
|
samer@38
|
246 { "h", "token keys help screen" }
|
samer@38
|
247 };
|
samer@38
|
248
|
samer@23
|
249 void melodyTriangle::keyPressed(int key){
|
hekeus@6
|
250 if (enableKeys){
|
samer@25
|
251 if (key>='2' && key<='9') {
|
samer@25
|
252 ratio=key-'0';
|
samer@25
|
253 } else {
|
samer@25
|
254 printf("got key: %d.\n",key);
|
samer@25
|
255 switch (key) {
|
samer@25
|
256
|
samer@38
|
257 case '<':
|
samer@25
|
258 if (tempoIndex>0) tempoIndex--;
|
samer@37
|
259 sender << msg("/tempo",tempi[tempoIndex]);
|
samer@25
|
260 break;
|
samer@38
|
261 case '>':
|
samer@32
|
262 if (tempoIndex<NUM_TEMPI-1) tempoIndex++;
|
samer@37
|
263 sender << msg("/tempo",tempi[tempoIndex]);
|
samer@25
|
264 break;
|
samer@25
|
265
|
samer@37
|
266 case ' ': sender << msg("/marker"); break;
|
samer@37
|
267 case 'S': sender << msg("/save"); break;
|
samer@37
|
268 case 'r': sender << msg("/report"); break;
|
samer@38
|
269 case 'I':
|
samer@37
|
270 randInit ^= true;
|
samer@37
|
271 display_msg = (randInit?"randomise on birth":"no randomise on birth");
|
samer@38
|
272 display_font = &main_font;
|
samer@37
|
273 display_frames = 40;
|
samer@37
|
274 break;
|
samer@37
|
275 case 'C': {
|
samer@37
|
276 ofxOscBundle bundle;
|
samer@37
|
277 sender << (bundle << msgReplyTo() << msgCalibrate());
|
samer@37
|
278 break;
|
samer@37
|
279 }
|
samer@25
|
280 case 'F': ofToggleFullscreen(); break;
|
samer@25
|
281 case 'R': reset(); break;
|
samer@25
|
282 case 'Q': ofAppGlutWindow::exitApp();
|
samer@38
|
283 case '/': display_frames=0; break;
|
samer@38
|
284 case 'h':
|
samer@38
|
285 case 'H':
|
samer@38
|
286 case '?':
|
samer@38
|
287 display_frames = -1;
|
samer@38
|
288 display_msg = help_string(key!='h');
|
samer@38
|
289 display_font = &help_font;
|
samer@38
|
290 break;
|
samer@38
|
291
|
samer@30
|
292 case OF_KEY_ESC: setKeyboardEnable(false); break;
|
samer@25
|
293
|
samer@25
|
294 default: // otherwise, send key to all voices under mouse
|
samer@25
|
295 for (int i=0; i<numVoices; i++)
|
samer@25
|
296 if (voices[i]->isInVoice(mouseX,mouseY))
|
samer@25
|
297 voiceKeypress(voices[i],key);
|
samer@12
|
298 }
|
hekeus@6
|
299 }
|
samer@30
|
300 } else {
|
samer@30
|
301 if (key==OF_KEY_ESC) setKeyboardEnable(true);
|
samer@37
|
302 else sender << msg("/key",key);
|
samer@30
|
303 }
|
samer@23
|
304 }
|
samer@23
|
305
|
samer@23
|
306 void melodyTriangle::voiceKeypress(Voice *v, int key) {
|
samer@23
|
307 switch (key) {
|
samer@25
|
308 case 'a':
|
samer@32
|
309 if (v->inTriangle) {
|
samer@37
|
310 sender << msg(v->isActive ? "/stop" : "/start", v->id);
|
samer@32
|
311 }
|
samer@23
|
312 v->isActive=!v->isActive;
|
samer@23
|
313 break;
|
samer@37
|
314 case OF_KEY_LEFT: sender << msgShift(v->id,-1,ratio); break;
|
samer@37
|
315 case OF_KEY_RIGHT: sender << msgShift(v->id,1,ratio); break;
|
samer@37
|
316 case OF_KEY_UP: sender << msgPeriod(v->id,1,ratio); break;
|
samer@37
|
317 case OF_KEY_DOWN: sender << msgPeriod(v->id,ratio,1); break;
|
samer@37
|
318 case ']': sender << msgOctave(v->id, ++v->octave); break;
|
samer@37
|
319 case '[': sender << msgOctave(v->id, --v->octave); break;
|
samer@38
|
320 case '}': sender << msgAmplitude(v->id, v->louder()); break;
|
samer@38
|
321 case '{': sender << msgAmplitude(v->id, v->quieter()); break;
|
samer@37
|
322 case 'c': sender << msg("/change",v->id); v->status=Voice::pending; break;
|
samer@38
|
323 case 's': sender << msg("/shuffle",v->id); break;
|
samer@23
|
324 default: printf("unrecognised key: %d.\n",key);
|
hekeus@6
|
325 }
|
hekeus@6
|
326 }
|
hekeus@6
|
327
|
samer@38
|
328 inline int max(int x, int y) { return y>x ? y : x; }
|
samer@38
|
329
|
samer@38
|
330 string melodyTriangle::help_string(bool global) {
|
samer@38
|
331 stringstream buf;
|
samer@38
|
332 struct command *cmds;
|
samer@38
|
333 int n, maxw=0;
|
samer@38
|
334
|
samer@38
|
335 buf << " ( " << (global ? "GLOBAL" : "TOKEN") << " KEYBOARD CONTROLS ) \n\n";
|
samer@38
|
336 if (global) { cmds=global_commands; n=NUMEL(global_commands); }
|
samer@38
|
337 else { cmds=voice_commands; n=NUMEL(voice_commands); }
|
samer@38
|
338
|
samer@38
|
339 for (int i=0; i<n; i++) maxw=max(maxw,strlen(cmds[i].key));
|
samer@38
|
340 for (int i=0; i<n; i++) buf << setw(maxw) << cmds[i].key << " - " << cmds[i].desc << "\n";
|
samer@38
|
341
|
samer@38
|
342 buf << "\nPress '/' to dismiss.";
|
samer@38
|
343 return buf.str();
|
samer@38
|
344 }
|
samer@38
|
345
|
samer@38
|
346
|
samer@22
|
347 //- Mouse ------------------------------------------------------
|
hekeus@6
|
348
|
samer@22
|
349 void melodyTriangle::mouseDragged(int x, int y, int button){}
|
samer@23
|
350 void melodyTriangle::mouseMoved(int x, int y ){}
|
samer@23
|
351 void melodyTriangle::mousePressed(int x, int y, int button){
|
samer@25
|
352 // pick up first token under mouse
|
hekeus@6
|
353 for (int i=0; i<numVoices;i++){
|
samer@25
|
354 if (voices[i]->isInVoice(x,y)) {
|
samer@25
|
355 voiceGrabbed=voices[i];
|
samer@25
|
356 break;
|
samer@25
|
357 }
|
hekeus@6
|
358 }
|
hekeus@6
|
359 }
|
hekeus@6
|
360
|
samer@22
|
361 void melodyTriangle::mouseReleased(int x, int y, int button){
|
samer@25
|
362 if (voiceGrabbed!=NULL) {
|
samer@25
|
363 Voice *v=voiceGrabbed;
|
samer@31
|
364 if (v->status==Voice::clear && v->truex>=0) {
|
samer@25
|
365 v->posx=v->truex;
|
samer@25
|
366 v->posy=v->truey;
|
samer@25
|
367 v->truex=v->truey=-1;
|
samer@25
|
368 }
|
samer@25
|
369 voiceGrabbed=NULL;
|
samer@25
|
370 }
|
hekeus@6
|
371 }
|
hekeus@6
|
372
|
hekeus@6
|
373 //--------------------------------------------------------------
|
samer@22
|
374
|
hekeus@6
|
375 void melodyTriangle::windowResized(int w, int h){
|
samer@22
|
376 fitTriangleIn(w,h);
|
samer@37
|
377 sender << msgCalibrate();
|
samer@23
|
378 reset();
|
samer@22
|
379 }
|
hekeus@6
|
380
|
samer@23
|
381 void melodyTriangle::reset() {
|
samer@25
|
382 voiceGrabbed=NULL;
|
samer@23
|
383 for (int i=0;i<numVoices;i++) {
|
samer@23
|
384 Voice *v=voices[i];
|
samer@23
|
385 v->posx=x2+RADIUS+(numVoices-1-i)*36;
|
samer@23
|
386 v->posy=48;
|
samer@23
|
387 v->status=Voice::pending;
|
samer@25
|
388 v->isActive=true;
|
samer@23
|
389 if (v->inTriangle) {
|
samer@37
|
390 sender << msg("/death",v->id);
|
samer@23
|
391 v->inTriangle=false;
|
samer@23
|
392 }
|
samer@23
|
393 }
|
samer@23
|
394 }
|
samer@22
|
395
|
samer@22
|
396 // OSC Message handling -----------------------------------------
|
samer@22
|
397
|
samer@23
|
398 Voice *melodyTriangle::get_voice(int id) throw(bad_voice_id) {
|
samer@30
|
399 for (int i=0; i<numVoices; i++) {
|
samer@30
|
400 if (voices[i]->id==id) return voices[i];
|
samer@30
|
401 }
|
samer@30
|
402 throw bad_voice_id(id);
|
samer@23
|
403 }
|
samer@23
|
404
|
samer@22
|
405 void melodyTriangle::handleMessage(ofxOscMessage &m) {
|
samer@22
|
406 string msg_path=m.getAddress();
|
samer@23
|
407
|
samer@23
|
408 try {
|
samer@23
|
409 if (msg_path.compare(0,8,"/notify/")==0) {
|
samer@25
|
410 string msg=msg_path.substr(8);
|
samer@23
|
411 Voice *v=get_voice(m.getArgAsInt32(0));
|
samer@25
|
412
|
samer@32
|
413 cout << "Received " << msg_path << "\n";
|
samer@25
|
414 if (msg=="requested") v->status=Voice::waiting;
|
samer@25
|
415 else if (msg=="pending") v->status=Voice::pending;
|
samer@25
|
416 else if (msg=="received") {
|
samer@25
|
417 float x=m.getArgAsFloat(1);
|
samer@25
|
418 float y=m.getArgAsFloat(2);
|
samer@25
|
419 v->status=Voice::clear;
|
samer@31
|
420 if (snapTruePos) {
|
samer@31
|
421 if (voiceGrabbed==v) {
|
samer@31
|
422 v->truex=x;
|
samer@31
|
423 v->truey=y;
|
samer@31
|
424 } else {
|
samer@31
|
425 v->posx=x;
|
samer@31
|
426 v->posy=y;
|
samer@31
|
427 v->truex=v->truey=-1;
|
samer@31
|
428 }
|
samer@25
|
429 }
|
samer@31
|
430 printf("True position of %d: %4.1f, %4.1f\n",v->id,x,y);
|
samer@25
|
431 } else if (msg=="position") {
|
samer@23
|
432 int x=(int)m.getArgAsFloat(1);
|
samer@23
|
433 int y=(int)m.getArgAsFloat(2);
|
samer@23
|
434 v->posx=x;
|
samer@23
|
435 v->posy=y;
|
samer@23
|
436 v->inTriangle=!clipToTriangle(&x,&y);
|
samer@31
|
437 v->status=Voice::clear;
|
samer@25
|
438 if (voiceGrabbed==v) voiceGrabbed=NULL;
|
samer@25
|
439 } else if (msg=="running") {
|
samer@23
|
440 v->isActive = m.getArgAsInt32(1) ? true : false;
|
samer@25
|
441 } else if (msg=="params") {
|
samer@23
|
442 v->octave = m.getArgAsInt32(1);
|
samer@23
|
443 v->amplitude = m.getArgAsFloat(2);
|
samer@32
|
444 } else if (msg=="visible") {
|
samer@32
|
445 v->isVisible = m.getArgAsInt32(1);
|
samer@32
|
446 if (voiceGrabbed==v && !v->isVisible)
|
samer@32
|
447 voiceGrabbed=NULL;
|
samer@23
|
448 }
|
samer@23
|
449 } else if (msg_path=="/display") {
|
samer@23
|
450 display_msg=m.getArgAsString(0);
|
samer@23
|
451 display_frames=m.getArgAsInt32(1);
|
samer@38
|
452 display_font=&main_font;
|
samer@23
|
453 } else if (msg_path=="/font") {
|
samer@38
|
454 main_font.loadFont(m.getArgAsString(0),m.getArgAsInt32(1));
|
samer@30
|
455 } else if (msg_path=="/keyboard") { setKeyboardEnable(m.getArgAsInt32(0)); }
|
samer@23
|
456 else if (msg_path=="/reset") { reset(); }
|
samer@23
|
457 else if (msg_path=="/fullscreen") { ofSetFullscreen(m.getArgAsInt32(0)); }
|
samer@23
|
458 else if (msg_path=="/quit") { ofAppGlutWindow::exitApp(); }
|
samer@30
|
459 else if (msg_path=="/allowExit") { allowExit=m.getArgAsInt32(0); }
|
samer@23
|
460 else {
|
samer@23
|
461 cout << m.getAddress();
|
samer@23
|
462 for (int i=0; i<m.getNumArgs(); i++) {
|
samer@23
|
463 cout << " " << m.getArgTypeName(i) << ":";
|
samer@23
|
464 switch (m.getArgType(i)) {
|
samer@23
|
465 case OFXOSC_TYPE_INT32: cout << m.getArgAsInt32(i);
|
samer@23
|
466 case OFXOSC_TYPE_FLOAT: cout << m.getArgAsFloat(i);
|
samer@23
|
467 case OFXOSC_TYPE_STRING: cout << m.getArgAsString(i);
|
samer@23
|
468 default: cout << "unknown";
|
samer@23
|
469 }
|
samer@23
|
470 }
|
samer@23
|
471 cout<< "\n";
|
samer@22
|
472 }
|
samer@23
|
473 } catch (std::exception &ex) {
|
samer@23
|
474 cout << "** Error processing OSC message: " << ex.what() << "\n";
|
samer@22
|
475 }
|
hekeus@6
|
476 }
|
samer@22
|
477
|
samer@30
|
478 void melodyTriangle::setKeyboardEnable(bool en) {
|
samer@30
|
479 enableKeys=en;
|
samer@31
|
480 snapTruePos=en;
|
samer@30
|
481 display_msg=en ? "Keyboard enabled" : "Keybard disabled";
|
samer@30
|
482 display_frames=40;
|
samer@38
|
483 display_font=&main_font;
|
samer@30
|
484 }
|
samer@30
|
485
|
samer@22
|
486 // OSC Message sending -----------------------------------------
|
samer@22
|
487
|
samer@37
|
488 ofxOscMessage melodyTriangle::msgPosition(Voice *v){
|
samer@22
|
489
|
samer@22
|
490 ofxOscMessage m;
|
samer@22
|
491 ///track id x y left right top bottom area
|
samer@22
|
492 m.setAddress( "/track2d" );
|
samer@23
|
493 m.addIntArg( v->id );
|
samer@23
|
494 m.addIntArg( v->posx );
|
samer@23
|
495 m.addIntArg( v->posy );
|
samer@37
|
496 // printf("/track2d %i %i %i\n",v->id,v->posx,v->posy);
|
samer@37
|
497 return m;
|
samer@22
|
498 }
|
samer@37
|
499
|
samer@37
|
500 ofxOscMessage melodyTriangle::msgCalibrate(){
|
samer@22
|
501 ofxOscMessage m;
|
samer@22
|
502 m.setAddress( "/calibrate" );
|
samer@22
|
503 m.addIntArg( x1 );
|
samer@22
|
504 m.addIntArg( y1 );
|
samer@22
|
505 m.addIntArg( x2 );
|
samer@22
|
506 m.addIntArg( y2 );
|
samer@22
|
507 m.addIntArg( x3 );
|
samer@22
|
508 m.addIntArg( y3 );
|
samer@37
|
509 printf("/calibrate %i %i %i %i %i %i\n",x1,y1,x2,y2,x3,y3);
|
samer@37
|
510 return m;
|
samer@22
|
511 }
|
samer@22
|
512
|
samer@37
|
513 ofxOscMessage melodyTriangle::msgReplyTo(){
|
samer@22
|
514 ofxOscMessage m;
|
samer@22
|
515 m.setAddress( "/reply_to" );
|
samer@22
|
516 m.addIntArg( receivePort );
|
samer@22
|
517 printf("sent /reply_to %i\n",receivePort);
|
samer@37
|
518 return m;
|
samer@22
|
519 }
|
samer@22
|
520
|
samer@37
|
521 ofxOscMessage melodyTriangle::msgPeriod(int id, int num, int den) { return msg("/period",id,num,den); }
|
samer@37
|
522 ofxOscMessage melodyTriangle::msgShift(int id, int num, int den) { return msg("/shift",id,num,den); }
|
samer@37
|
523 ofxOscMessage melodyTriangle::msgOctave(int id, int oct) { return msg("/octave",id,oct); }
|
samer@22
|
524
|
samer@37
|
525 ofxOscMessage melodyTriangle::msgAmplitude(int id, float amp){
|
samer@22
|
526 ofxOscMessage m;
|
samer@22
|
527 m.setAddress("/amplitude");
|
samer@22
|
528 m.addIntArg(id);
|
samer@22
|
529 m.addFloatArg(amp);
|
samer@37
|
530 printf("/amplitude %i %1.3f\n",id,amp);
|
samer@37
|
531 return m;
|
samer@22
|
532 }
|
samer@22
|
533
|
samer@37
|
534 ofxOscMessage melodyTriangle::msg(const char *addr, int a, int b, int c) {
|
samer@32
|
535 ofxOscMessage m;
|
samer@32
|
536 m.setAddress(addr);
|
samer@32
|
537 m.addIntArg(a);
|
samer@32
|
538 m.addIntArg(b);
|
samer@32
|
539 m.addIntArg(c);
|
samer@37
|
540 printf("%s %i %i %i\n",addr,a,b,c);
|
samer@37
|
541 return m;
|
samer@32
|
542 }
|
samer@32
|
543
|
samer@37
|
544 ofxOscMessage melodyTriangle::msg(const char *addr, int a, int b) {
|
samer@32
|
545 ofxOscMessage m;
|
samer@32
|
546 m.setAddress(addr);
|
samer@32
|
547 m.addIntArg(a);
|
samer@32
|
548 m.addIntArg(b);
|
samer@37
|
549 printf("%s %i %i\n",addr,a,b);
|
samer@37
|
550 return m;
|
samer@32
|
551 }
|
samer@32
|
552
|
samer@37
|
553 ofxOscMessage melodyTriangle::msg(const char *addr, int a) {
|
samer@25
|
554 ofxOscMessage m;
|
samer@25
|
555 m.setAddress(addr);
|
samer@25
|
556 m.addIntArg(a);
|
samer@37
|
557 printf("%s %i\n",addr,a);
|
samer@37
|
558 return m;
|
samer@25
|
559 }
|
samer@25
|
560
|
samer@37
|
561 ofxOscMessage melodyTriangle::msg(const char *addr) {
|
samer@25
|
562 ofxOscMessage m;
|
samer@25
|
563 m.setAddress(addr);
|
samer@37
|
564 printf("%s\n",addr);
|
samer@37
|
565 return m;
|
samer@25
|
566 }
|
samer@22
|
567
|
samer@22
|
568 void melodyTriangle::fitTriangleIn(int width, int height) {
|
samer@22
|
569 int triHeight = height*0.75;
|
samer@22
|
570 int triHalfWidth = triHeight/sqrt(3);
|
samer@22
|
571
|
samer@22
|
572 x1=width/2;
|
samer@22
|
573 x2=x1-triHalfWidth;
|
samer@22
|
574 x3=x1+triHalfWidth;
|
samer@22
|
575 y1=(height-triHeight)/2;
|
samer@22
|
576 y2=y3=height - (height-triHeight)/2;
|
samer@22
|
577
|
samer@22
|
578 // used for clipping
|
samer@22
|
579 DX13=x3-x1; DY13=y3-y1;
|
samer@22
|
580 SQLEN13=DX13*DX13+DY13*DY13;
|
samer@22
|
581 }
|
samer@23
|
582
|
samer@23
|
583 const char *melodyTriangle::bad_voice_id::what() const throw() {
|
samer@23
|
584 std::stringstream out;
|
samer@23
|
585 printf("bad_voice_id(%d).\n",id);
|
samer@30
|
586 out << "Voice id " << id <<" not present.";
|
samer@23
|
587 return out.str().c_str();
|
samer@23
|
588 }
|