annotate scanpath.mm @ 15:d5758530a039 tip

oF0.84 Retina, and iPhone support
author Robert Tubb <rt300@eecs.qmul.ac.uk>
date Tue, 12 May 2015 15:48:52 +0100
parents 4ba81a12b008
children
rev   line source
rt300@0 1 /*
rt300@0 2 * scanpath.cpp
rt300@0 3 * springstructure
rt300@0 4 *
rt300@0 5 * Created by Robert Tubb on 09/06/2011.
rt300@0 6 * Copyright 2011 __MyCompanyName__. All rights reserved.
rt300@0 7 *
rt300@0 8 */
rt300@0 9 #include <vector>
rt300@0 10 #include "scanpath.h"
rt300@0 11 #include "testApp.h"
rt300@0 12
rt300@3 13 ScanPath scanPath;
rt300@3 14
rt300@3 15 // audio thread does not touch mesh lumps/springs
rt300@0 16 //----------------------------------------------------------------
rt300@3 17 ScanPath::ScanPath() : maxElements(10000) {
rt300@0 18 // construct an empty scanpath
rt300@0 19 // an ' element ' consists of 1 lump and one spring
rt300@0 20
rt300@0 21
rt300@0 22 numElements = 0; // numElements is a dynamic running count of elements when building - a bit crap
rt300@3 23
rt300@0 24
rt300@0 25 frameInterpolator = 0.0;
rt300@0 26 currentLength = 0.0;
rt300@0 27 restLength = 1.0; // ?
rt300@0 28
rt300@0 29 scanMode = DISPLACEMENT;
rt300@3 30 initWavetables();
rt300@3 31 framesPerSample = 60.0/SAMPLE_RATE;
rt300@4 32 updateAccessing = false;
rt300@4 33 audioAccessing = false;
rt300@4 34
rt300@3 35 }
rt300@3 36 void ScanPath::init(){
rt300@3 37 framesPerSample = ofGetFrameRate()/SAMPLE_RATE;
rt300@0 38
rt300@0 39 }
rt300@0 40 //----------------------------------------------------------------
rt300@0 41 ScanPath::~ScanPath(){
rt300@4 42
rt300@3 43
rt300@0 44 delete [] wavetableNew;
rt300@0 45 delete [] wavetableOld;
rt300@0 46 delete [] wavetableUpdate;
rt300@0 47 cout << "destructed scanpath\n";
rt300@0 48 }
rt300@0 49
rt300@0 50 void ScanPath::clear(){
rt300@4 51
rt300@3 52 for(vector<Element>::iterator elitr = pathElements.begin(); elitr < pathElements.end(); elitr++){
rt300@3 53 (*elitr).eLump->removeFromScanPath();
rt300@3 54 (*elitr).eSpring->removeFromScanPath();
rt300@0 55 }
rt300@3 56 pathElements.clear();
rt300@0 57 numElements = 0;
rt300@3 58
rt300@0 59 }
rt300@0 60 int ScanPath::howManyElements(){
rt300@3 61 //return pathElements.size();
rt300@0 62 return numElements;
rt300@0 63 }
rt300@0 64 //----------------------------------------------------------------
rt300@0 65 void ScanPath::inscribe(double ax, double ay){
rt300@0 66 // look at coordinates, add the closest lump and it's connecting string
rt300@0 67 // if we're further away from current lump
rt300@0 68
rt300@0 69 // check end points of connecting springs, pick closest
rt300@3 70
rt300@3 71 // NOW IN MESH
rt300@0 72 }
rt300@0 73 void ScanPath::draw(){
rt300@0 74 // draw the actual waveform in the corner
rt300@0 75
rt300@0 76 int width = 768;
rt300@0 77 int height = 128;
rt300@0 78 double sampval = 0.0;
rt300@0 79 int leftsampnum = 0;
rt300@0 80 int rightsampnum = 0;
rt300@0 81 float sampscale = 0.0, prevsampscale = 0.0, interp = 0.0;
rt300@0 82
rt300@8 83 ofSetColor(256, 0, 0);
rt300@0 84 double step = double(numElements)/width; // how much we are stepping thru wave per pixel
rt300@0 85 for(int i = 0; i < width; i++){
rt300@0 86
rt300@0 87 leftsampnum = floor(i * step); // basic nearest neighbour interpolation
rt300@0 88 rightsampnum = ceil(i*step);
rt300@0 89 interp = (i*step)-leftsampnum;
rt300@0 90 if(rightsampnum < numElements){
rt300@0 91 sampval = (1 - interp)*wavetableNew[leftsampnum] + interp*wavetableNew[rightsampnum];
rt300@0 92 }
rt300@0 93 sampscale = (sampval * 700) + height/2.0; // centre and scale
rt300@0 94 ofSetLineWidth(2);
rt300@0 95 ofLine(sampscale, i, prevsampscale, i-1); // draw a line from pixel to pixel (?)
rt300@0 96 prevsampscale = sampscale;
rt300@0 97 }
rt300@0 98
rt300@0 99 }
rt300@0 100 void drawCubic(){
rt300@0 101
rt300@0 102 }
rt300@0 103 //----------------------------------------------------------------
rt300@0 104 // add spring
rt300@0 105 void ScanPath::addSpring(){
rt300@0 106 // see add element
rt300@0 107 }
rt300@0 108 //----------------------------------------------------------------
rt300@0 109 // add lump
rt300@0 110 void ScanPath::addLump(){
rt300@0 111 // see add element
rt300@0 112 }
rt300@0 113 //----------------------------------------------------------------
rt300@0 114 // add lump
rt300@0 115 double ScanPath::getTotalLength(){
rt300@0 116 // for interesting modulations...
rt300@0 117 currentLength = 0.0;
rt300@3 118
rt300@3 119 for(vector<Element>::iterator elitr = pathElements.begin(); elitr < pathElements.end(); elitr++){
rt300@3 120
rt300@3 121 currentLength = (*elitr).eSpring->getLength();
rt300@0 122 }
rt300@0 123 return currentLength;
rt300@0 124
rt300@0 125 }
rt300@0 126 //----------------------------------------------------------------
rt300@0 127 void ScanPath::initWavetables(){
rt300@0 128 wavetableNew = new double[maxElements];
rt300@0 129 wavetableOld = new double[maxElements];
rt300@0 130 wavetableUpdate = new double[maxElements];
rt300@0 131
rt300@0 132 for(int i = 0; i < maxElements; i++){
rt300@0 133 wavetableOld[i] = 0.0;
rt300@0 134 wavetableNew[i] = 0.0;
rt300@0 135 wavetableUpdate[i] = 0.0;
rt300@0 136 }
rt300@0 137
rt300@0 138 }
rt300@0 139 //----------------------------------------------------------------
rt300@3 140 void ScanPath::addElement(Lump* const aLump, Spring * const aSpring){
rt300@0 141 // insert ptr to the lump and spring into array
rt300@3 142
rt300@3 143
rt300@3 144 if(numElements + 1 >= maxElements){
rt300@3 145 cout << " max elements reached!\n";
rt300@0 146 return;
rt300@0 147 }
rt300@3 148
rt300@3 149 pathElements.push_back(Element(aLump,aSpring));
rt300@0 150
rt300@3 151 // maybe do this in mesh?
rt300@0 152 aLump->addToScanPath();
rt300@0 153 aSpring->addToScanPath();
rt300@3 154 numElements++;
rt300@0 155
rt300@3 156
rt300@0 157 }
rt300@0 158 //----------------------------------------------------------------
rt300@8 159 Lump * ScanPath::getLump(int index){
rt300@8 160 if(index < pathElements.size()){
rt300@8 161 return pathElements[index].eLump;
rt300@8 162 }else{
rt300@8 163 cerr << "bad scanpath::getLump index\n";
rt300@8 164 return NULL;
rt300@8 165 }
rt300@8 166
rt300@8 167 }
rt300@8 168 //----------------------------------------------------------------
rt300@8 169 Spring * ScanPath::getSpring(int index){
rt300@8 170 if(index < pathElements.size()){
rt300@8 171 return pathElements[index].eSpring;
rt300@8 172 }else{
rt300@8 173 cerr << "bad scanpath::getSpring index\n";
rt300@8 174 return NULL;
rt300@8 175 }
rt300@8 176 }
rt300@8 177
rt300@8 178 //----------------------------------------------------------------
rt300@0 179 void ScanPath::updateWavetables(){
rt300@0 180 // swap old , new
rt300@0 181 double * temp;
rt300@5 182 if(pathElements.size() == 0) return;
rt300@1 183 // TODO THRED MUTEX HERE!??
rt300@3 184 // this is called from graphics thread
rt300@3 185 // reset the interp between frames
rt300@5 186 /*
rt300@3 187 int i = 0;
rt300@3 188 while(audioAccessing){
rt300@3 189 i++;
rt300@3 190 }
rt300@4 191 if(i > 0){
rt300@4 192 cout << "Update wavetables had to wait for audio access " << i << " times\n";
rt300@4 193 // hardly ever happens
rt300@4 194 }
rt300@5 195 */
rt300@3 196 updateAccessing = true;
rt300@3 197
rt300@4 198
rt300@0 199 switch(scanMode){
rt300@0 200 case DISPLACEMENT:
rt300@0 201 // now fill with new values
rt300@0 202 for(int i = 0; i < numElements; i++){
rt300@3 203 // double check
rt300@5 204
rt300@8 205 wavetableUpdate[i] = pathElements[i].eLump->scanDisplacement();
rt300@5 206
rt300@0 207
rt300@0 208 }
rt300@0 209 break;
rt300@0 210 case SPEED:
rt300@0 211 for(int i = 0; i < numElements; i++){
rt300@5 212
rt300@5 213 wavetableUpdate[i] = pathElements[i].eLump->scanLumpSpeed();
rt300@5 214
rt300@0 215 }
rt300@0 216 break;
rt300@0 217 case SPRING_FORCE:
rt300@0 218 for(int i = 0; i < numElements; i++){
rt300@3 219 if(pathElements[i].eSpring->isInScanPath){
rt300@3 220 wavetableUpdate[i] = pathElements[i].eSpring->getForceMag();
rt300@3 221 }
rt300@0 222 }
rt300@0 223 break;
rt300@0 224 case YPOS:
rt300@0 225 for(int i = 0; i < numElements; i++){
rt300@3 226 if(pathElements[i].eLump->isInScanPath){
rt300@3 227 wavetableUpdate[i] = pathElements[i].eLump->scanYPos();
rt300@3 228 }
rt300@0 229 }
rt300@0 230 break;
rt300@0 231 default:
rt300@0 232 break;
rt300@4 233
rt300@0 234 }
rt300@4 235
rt300@0 236 temp = wavetableOld;
rt300@0 237 wavetableOld = wavetableNew;
rt300@0 238 wavetableNew = wavetableUpdate;
rt300@0 239 wavetableUpdate = temp;
rt300@3 240
rt300@3 241 // END THREAD MUTEX
rt300@0 242 updateAccessing = false;
rt300@0 243
rt300@0 244 frameInterpolator = 0.0;
rt300@0 245 framesPerSample = 2.0*ofGetFrameRate()/SAMPLE_RATE; // attempt to get a reasonable est. of how fast to interp
rt300@0 246
rt300@0 247 }
rt300@0 248 //----------------------------------------------------------------
rt300@3 249 //----------------------------------------------------------------
rt300@3 250 // AUDIO THREAD STUFF
rt300@3 251 //----------------------------------------------------------------
rt300@0 252 // get next sample
rt300@3 253
rt300@0 254 double ScanPath::getNextSample(double aPhasor){
rt300@0 255 // move along path, interpolating between points
rt300@0 256 // move between frames too
rt300@5 257 if(pathElements.size() == 0) return 0.0;
rt300@5 258
rt300@0 259 double alongPath = aPhasor*double(numElements);
rt300@0 260
rt300@0 261 // indexes for interpolated points
rt300@0 262 int n0 = floor(alongPath);
rt300@0 263 int n1 = n0+1;
rt300@0 264 if(n1 >= numElements){
rt300@0 265 n1 = 0;
rt300@0 266 }
rt300@0 267
rt300@0 268 double frac = alongPath - double(n0);
rt300@0 269
rt300@3 270 // TODO THRED MUTEX HERE!??
rt300@3 271 // this is called from audio thread
rt300@5 272 /*
rt300@3 273 int i = 0;
rt300@3 274 while(updateAccessing){
rt300@3 275 i++;
rt300@3 276 }
rt300@5 277 */
rt300@0 278 audioAccessing = true;
rt300@5 279 // if(i>0) cout << "Audio thread had to wait for wavetable update " << i << " times\n";
rt300@4 280
rt300@1 281
rt300@0 282 double oldsample = (1 - frac) * wavetableOld[n0] + frac * wavetableOld[n1];
rt300@0 283
rt300@0 284 double newsample = (1 - frac) * wavetableNew[n0] + frac * wavetableNew[n1];
rt300@0 285
rt300@1 286 // END THREAD MUTEX
rt300@0 287 audioAccessing = false;
rt300@0 288
rt300@0 289 frameInterpolator += framesPerSample;
rt300@0 290 if(frameInterpolator >= 1.0){
rt300@0 291 //cout << "frame interp > 1\n";
rt300@0 292 frameInterpolator = 1.0; // just stays outputting new
rt300@0 293 }
rt300@0 294
rt300@0 295 double sample = (1 - frameInterpolator)*oldsample + frameInterpolator*newsample;
rt300@0 296 //cout << sample << endl;
rt300@0 297 // keep within the bounds of acceptability
rt300@14 298
rt300@0 299 return sample;
rt300@0 300
rt300@0 301 }
rt300@0 302 //----------------------------------------------------------------
rt300@13 303 // get next sample: just one sample at a time at sample rate
rt300@0 304 double ScanPath::getNextSample(){
rt300@0 305 // move along wavetable, no interpolation ie: length of path is pitch
rt300@0 306 static int n = 0;
rt300@0 307 double oldsample = wavetableOld[n];
rt300@0 308
rt300@0 309 double newsample = wavetableNew[n];
rt300@0 310 n++;
rt300@0 311 if (n >= numElements){
rt300@0 312 n = 0;
rt300@0 313 }
rt300@0 314
rt300@0 315 frameInterpolator += framesPerSample;
rt300@0 316 if(frameInterpolator >= 1.0){
rt300@0 317 //cout << "frame interp > 1\n";
rt300@0 318 frameInterpolator = 1.0; // just stays outputting new
rt300@0 319 }
rt300@0 320
rt300@0 321 double sample = (1 - frameInterpolator)*oldsample + frameInterpolator*newsample;
rt300@13 322 // beef up
rt300@13 323 sample = sample*10.0;
rt300@13 324
rt300@13 325 if(sample > 0.99){
rt300@13 326 cout << "BIG" << endl;
rt300@13 327
rt300@13 328 sample = 0.99;
rt300@13 329 }else if(sample < -0.0){
rt300@13 330 cout << "SMALL" << endl;
rt300@13 331 sample = 0.0;
rt300@13 332 }
rt300@0 333
rt300@0 334 }
rt300@0 335 //----------------------------------------------------------------
rt300@0 336 //----------------------------------------------------------------
rt300@0 337 // get next sample with cubic interpolation
rt300@0 338 double ScanPath::getNextSampleCubic(double aPhasor){
rt300@0 339 // move along path, interpolating between points
rt300@0 340 // move between frames too
rt300@0 341 double alongPath = aPhasor*double(numElements);
rt300@0 342
rt300@0 343 // indexes for interpolated points
rt300@0 344 int n1 = floor(alongPath);
rt300@0 345
rt300@0 346 int n0 = n1-1;
rt300@0 347 if(n0 < 0){
rt300@0 348 n0 = numElements;
rt300@0 349 }
rt300@0 350 int n2 = n1+1;
rt300@0 351 if(n2 >= numElements){
rt300@0 352 n2 = 0;
rt300@0 353 }
rt300@0 354 int n3 = n2+1;
rt300@0 355 if(n3 >= numElements){
rt300@0 356 n3 = 0;
rt300@0 357 }
rt300@0 358 double frac = alongPath - double(n0);
rt300@0 359 double fracSquared = frac * frac;
rt300@0 360 double fracCubed = fracSquared * frac;
rt300@0 361 double a0,a1,a2,a3;
rt300@0 362 //cout << n0 << endl;
rt300@0 363 // cubic interp
rt300@0 364 /*
rt300@0 365 double y0,double y1,
rt300@0 366 double y2,double y3,
rt300@0 367 double mu)
rt300@0 368 {
rt300@0 369 double a0,a1,a2,a3,mu2;
rt300@0 370
rt300@0 371 mu2 = mu*mu;
rt300@0 372 a0 = y3 - y2 - y0 + y1;
rt300@0 373 a1 = y0 - y1 - a0;
rt300@0 374 a2 = y2 - y0;
rt300@0 375 a3 = y1;
rt300@0 376
rt300@0 377 return(a0*mu*mu2+a1*mu2+a2*mu+a3);
rt300@0 378 */
rt300@0 379 a0 = wavetableOld[n3] - wavetableOld[n2] - wavetableOld[n0] + wavetableOld[n1];
rt300@0 380 a1 = wavetableOld[n0] - wavetableOld[n1] - a0; // y0 - y1 - a0;
rt300@0 381 a2 = wavetableOld[n2] - wavetableOld[n0]; // y2 - y0;
rt300@0 382 a3 = wavetableOld[n1];
rt300@0 383
rt300@0 384 double oldsample = a0*fracCubed + a1*fracSquared + a2*frac + a3;
rt300@0 385
rt300@0 386 a0 = wavetableNew[n3] - wavetableNew[n2] - wavetableNew[n0] + wavetableNew[n1];
rt300@0 387 a1 = wavetableNew[n0] - wavetableNew[n1] - a0; // y0 - y1 - a0;
rt300@0 388 a2 = wavetableNew[n2] - wavetableNew[n0]; // y2 - y0;
rt300@0 389 a3 = wavetableNew[n1];
rt300@0 390
rt300@0 391 double newsample = a0*fracCubed + a1*fracSquared + a2*frac + a3;
rt300@0 392
rt300@0 393 frameInterpolator += framesPerSample;
rt300@0 394 if(frameInterpolator >= 1.0){
rt300@0 395 frameInterpolator = 1.0; // just stays outputting new
rt300@0 396 }
rt300@0 397
rt300@0 398 double sample = (1 - frameInterpolator)*oldsample + frameInterpolator*newsample;
rt300@0 399 //cout << sample << endl;
rt300@0 400 // keep within the bounds of acceptability
rt300@0 401
rt300@0 402 // beef up
rt300@13 403 sample = sample*10.0;
rt300@0 404
rt300@0 405 if(sample > 0.99){
rt300@13 406 cout << "BIG" << endl;
rt300@13 407
rt300@0 408 sample = 0.99;
rt300@13 409 }else if(sample < -0.0){
rt300@13 410 cout << "SMALL" << endl;
rt300@13 411 sample = 0.0;
rt300@0 412 }
rt300@0 413
rt300@0 414 return sample;
rt300@0 415
rt300@0 416 }
rt300@8 417 //----------------------------------------------------------------
rt300@8 418
rt300@8 419 Json::Value ScanPath::convertToJsonForSaving(){
rt300@8 420 Json::Value jscanpath;
rt300@9 421
rt300@9 422 for(int i=0;i<pathElements.size();i++){
rt300@9 423 //scanPath.addElement(&lumps[scanPathElements[i]["lumpNo"].asInt()], &springs[scanPathElements[i]["springNo"].asInt()]);
rt300@9 424 jscanpath[i]["lumpNo"] = pathElements[i].eLump->myIndexInMesh;
rt300@9 425 jscanpath[i]["springNo"] = pathElements[i].eSpring->myIndexInMesh;
rt300@9 426 }
rt300@9 427
rt300@8 428 return jscanpath;
rt300@8 429 }
rt300@8 430
rt300@8 431 //----------------------------------------------------------------
rt300@8 432
rt300@8 433 //----------------------------------------------------------------
rt300@8 434
rt300@8 435 //----------------------------------------------------------------
rt300@8 436