annotate src/melodyTriangle.cpp @ 37:260cc4f4d70a

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