rt300@0: /* rt300@0: * scanpath.cpp rt300@0: * springstructure rt300@0: * rt300@0: * Created by Robert Tubb on 09/06/2011. rt300@0: * Copyright 2011 __MyCompanyName__. All rights reserved. rt300@0: * rt300@0: */ rt300@0: #include rt300@0: #include "scanpath.h" rt300@0: #include "testApp.h" rt300@0: rt300@0: //---------------------------------------------------------------- rt300@0: ScanPath::ScanPath() : maxElements(2048) { rt300@0: // construct an empty scanpath rt300@0: // an ' element ' consists of 1 lump and one spring rt300@0: rt300@0: rt300@0: numElements = 0; // numElements is a dynamic running count of elements when building - a bit crap rt300@0: springPath = new Spring*[maxElements]; rt300@0: lumpPath = new Lump*[maxElements]; rt300@0: rt300@0: framesPerSample = ofGetFrameRate()/SAMPLE_RATE; rt300@0: frameInterpolator = 0.0; rt300@0: currentLength = 0.0; rt300@0: restLength = 1.0; // ? rt300@0: rt300@0: scanMode = DISPLACEMENT; rt300@0: rt300@0: initWavetables(); rt300@0: rt300@0: } rt300@0: //---------------------------------------------------------------- rt300@0: ScanPath::~ScanPath(){ rt300@0: delete [] springPath; rt300@0: delete [] lumpPath; rt300@0: delete [] wavetableNew; rt300@0: delete [] wavetableOld; rt300@0: delete [] wavetableUpdate; rt300@0: cout << "destructed scanpath\n"; rt300@0: } rt300@0: rt300@0: void ScanPath::clear(){ rt300@0: for(int i = 0; iremoveFromScanPath(); rt300@0: lumpPath[i]->removeFromScanPath(); rt300@0: } rt300@0: numElements = 0; rt300@0: // cant work? rt300@0: } rt300@0: int ScanPath::howManyElements(){ rt300@0: return numElements; rt300@0: } rt300@0: //---------------------------------------------------------------- rt300@0: void ScanPath::inscribe(double ax, double ay){ rt300@0: // look at coordinates, add the closest lump and it's connecting string rt300@0: // if we're further away from current lump rt300@0: rt300@0: // check end points of connecting springs, pick closest rt300@0: } rt300@0: void ScanPath::draw(){ rt300@0: // draw the actual waveform in the corner rt300@0: rt300@0: int width = 768; rt300@0: int height = 128; rt300@0: double sampval = 0.0; rt300@0: int leftsampnum = 0; rt300@0: int rightsampnum = 0; rt300@0: float sampscale = 0.0, prevsampscale = 0.0, interp = 0.0; rt300@0: rt300@0: ofSetColor(0, 0, 0); rt300@0: double step = double(numElements)/width; // how much we are stepping thru wave per pixel rt300@0: for(int i = 0; i < width; i++){ rt300@0: rt300@0: leftsampnum = floor(i * step); // basic nearest neighbour interpolation rt300@0: rightsampnum = ceil(i*step); rt300@0: interp = (i*step)-leftsampnum; rt300@0: if(rightsampnum < numElements){ rt300@0: sampval = (1 - interp)*wavetableNew[leftsampnum] + interp*wavetableNew[rightsampnum]; rt300@0: } rt300@0: sampscale = (sampval * 700) + height/2.0; // centre and scale rt300@0: ofSetLineWidth(2); rt300@0: ofLine(sampscale, i, prevsampscale, i-1); // draw a line from pixel to pixel (?) rt300@0: prevsampscale = sampscale; rt300@0: } rt300@0: rt300@0: } rt300@0: void drawCubic(){ rt300@0: rt300@0: } rt300@0: //---------------------------------------------------------------- rt300@0: // add spring rt300@0: void ScanPath::addSpring(){ rt300@0: // see add element rt300@0: } rt300@0: //---------------------------------------------------------------- rt300@0: // add lump rt300@0: void ScanPath::addLump(){ rt300@0: // see add element rt300@0: } rt300@0: //---------------------------------------------------------------- rt300@0: // add lump rt300@0: double ScanPath::getTotalLength(){ rt300@0: // for interesting modulations... rt300@0: currentLength = 0.0; rt300@0: for(int i = 0; i < numElements; i++){ rt300@0: currentLength += springPath[i]->getLength(); rt300@0: } rt300@0: return currentLength; rt300@0: rt300@0: } rt300@0: //---------------------------------------------------------------- rt300@0: void ScanPath::initWavetables(){ rt300@0: wavetableNew = new double[maxElements]; rt300@0: wavetableOld = new double[maxElements]; rt300@0: wavetableUpdate = new double[maxElements]; rt300@0: rt300@0: for(int i = 0; i < maxElements; i++){ rt300@0: wavetableOld[i] = 0.0; rt300@0: wavetableNew[i] = 0.0; rt300@0: wavetableUpdate[i] = 0.0; rt300@0: } rt300@0: rt300@0: } rt300@0: //---------------------------------------------------------------- rt300@0: void ScanPath::addElement(Lump* aLump, Spring * aSpring){ rt300@0: // insert ptr to the lump and spring into array rt300@0: if(numElements >= maxElements){ rt300@0: cerr << "cannot add any more to scanpath - max elements: 2048\n"; rt300@0: return; rt300@0: } rt300@0: lumpPath[numElements] = aLump; rt300@0: springPath[numElements] = aSpring; rt300@0: rt300@0: aLump->addToScanPath(); rt300@0: aSpring->addToScanPath(); rt300@0: rt300@0: numElements++; rt300@0: } rt300@0: //---------------------------------------------------------------- rt300@0: void ScanPath::updateWavetables(){ rt300@0: // swap old , new rt300@0: double * temp; rt300@0: rt300@1: // TODO THRED MUTEX HERE!?? rt300@1: rt300@0: switch(scanMode){ rt300@0: case DISPLACEMENT: rt300@0: // now fill with new values rt300@0: for(int i = 0; i < numElements; i++){ rt300@0: rt300@0: wavetableUpdate[i] = lumpPath[i]->scanRadialDisplacement()/1.5; rt300@0: rt300@0: } rt300@0: break; rt300@0: case SPEED: rt300@0: for(int i = 0; i < numElements; i++){ rt300@0: wavetableUpdate[i] = lumpPath[i]->scanLumpSpeed(); rt300@0: } rt300@0: break; rt300@0: case SPRING_FORCE: rt300@0: for(int i = 0; i < numElements; i++){ rt300@0: wavetableUpdate[i] = springPath[i]->getForceMag(); rt300@0: } rt300@0: break; rt300@0: case YPOS: rt300@0: for(int i = 0; i < numElements; i++){ rt300@0: wavetableUpdate[i] = lumpPath[i]->scanYPos(); rt300@0: } rt300@0: break; rt300@0: default: rt300@0: break; rt300@0: rt300@0: rt300@0: } rt300@1: rt300@1: // END THREAD MUTEX rt300@0: rt300@0: // reset the interp between frames rt300@0: if(audioAccessing){ rt300@0: cout << "buffers swapped while update!\n"; rt300@0: } rt300@0: updateAccessing = true; rt300@0: temp = wavetableOld; rt300@0: wavetableOld = wavetableNew; rt300@0: wavetableNew = wavetableUpdate; rt300@0: wavetableUpdate = temp; rt300@0: updateAccessing = false; rt300@0: rt300@0: frameInterpolator = 0.0; rt300@0: framesPerSample = 2.0*ofGetFrameRate()/SAMPLE_RATE; // attempt to get a reasonable est. of how fast to interp rt300@0: rt300@0: } rt300@0: //---------------------------------------------------------------- rt300@0: // get next sample rt300@0: double ScanPath::getNextSample(double aPhasor){ rt300@0: // move along path, interpolating between points rt300@0: // move between frames too rt300@0: double alongPath = aPhasor*double(numElements); rt300@0: rt300@0: // indexes for interpolated points rt300@0: int n0 = floor(alongPath); rt300@0: int n1 = n0+1; rt300@0: if(n1 >= numElements){ rt300@0: n1 = 0; rt300@0: } rt300@0: rt300@0: double frac = alongPath - double(n0); rt300@0: rt300@0: audioAccessing = true; rt300@0: if (updateAccessing){ rt300@0: cout << "update is accessing while audio is\n"; rt300@0: } rt300@1: rt300@1: // TODO THRED MUTEX HERE!?? rt300@1: rt300@0: double oldsample = (1 - frac) * wavetableOld[n0] + frac * wavetableOld[n1]; rt300@0: rt300@0: double newsample = (1 - frac) * wavetableNew[n0] + frac * wavetableNew[n1]; rt300@0: rt300@1: // END THREAD MUTEX rt300@0: audioAccessing = false; rt300@0: rt300@0: frameInterpolator += framesPerSample; rt300@0: if(frameInterpolator >= 1.0){ rt300@0: //cout << "frame interp > 1\n"; rt300@0: frameInterpolator = 1.0; // just stays outputting new rt300@0: } rt300@0: rt300@0: double sample = (1 - frameInterpolator)*oldsample + frameInterpolator*newsample; rt300@0: //cout << sample << endl; rt300@0: // keep within the bounds of acceptability rt300@0: if(sample > 0.99){ rt300@0: // cout << "OUCH\n"; rt300@0: sample = 0.99; rt300@0: }else if(sample < -0.99){ rt300@0: sample = -0.99; rt300@0: } rt300@0: return sample; rt300@0: rt300@0: } rt300@0: //---------------------------------------------------------------- rt300@0: // get next sample rt300@0: double ScanPath::getNextSample(){ rt300@0: // move along wavetable, no interpolation ie: length of path is pitch rt300@0: static int n = 0; rt300@0: double oldsample = wavetableOld[n]; rt300@0: rt300@0: double newsample = wavetableNew[n]; rt300@0: n++; rt300@0: if (n >= numElements){ rt300@0: n = 0; rt300@0: } rt300@0: rt300@0: frameInterpolator += framesPerSample; rt300@0: if(frameInterpolator >= 1.0){ rt300@0: //cout << "frame interp > 1\n"; rt300@0: frameInterpolator = 1.0; // just stays outputting new rt300@0: } rt300@0: rt300@0: double sample = (1 - frameInterpolator)*oldsample + frameInterpolator*newsample; rt300@0: return sample*3.0; rt300@0: rt300@0: } rt300@0: //---------------------------------------------------------------- rt300@0: //---------------------------------------------------------------- rt300@0: // get next sample with cubic interpolation rt300@0: double ScanPath::getNextSampleCubic(double aPhasor){ rt300@0: // move along path, interpolating between points rt300@0: // move between frames too rt300@0: double alongPath = aPhasor*double(numElements); rt300@0: rt300@0: // indexes for interpolated points rt300@0: int n1 = floor(alongPath); rt300@0: rt300@0: int n0 = n1-1; rt300@0: if(n0 < 0){ rt300@0: n0 = numElements; rt300@0: } rt300@0: int n2 = n1+1; rt300@0: if(n2 >= numElements){ rt300@0: n2 = 0; rt300@0: } rt300@0: int n3 = n2+1; rt300@0: if(n3 >= numElements){ rt300@0: n3 = 0; rt300@0: } rt300@0: double frac = alongPath - double(n0); rt300@0: double fracSquared = frac * frac; rt300@0: double fracCubed = fracSquared * frac; rt300@0: double a0,a1,a2,a3; rt300@0: //cout << n0 << endl; rt300@0: // cubic interp rt300@0: /* rt300@0: double y0,double y1, rt300@0: double y2,double y3, rt300@0: double mu) rt300@0: { rt300@0: double a0,a1,a2,a3,mu2; rt300@0: rt300@0: mu2 = mu*mu; rt300@0: a0 = y3 - y2 - y0 + y1; rt300@0: a1 = y0 - y1 - a0; rt300@0: a2 = y2 - y0; rt300@0: a3 = y1; rt300@0: rt300@0: return(a0*mu*mu2+a1*mu2+a2*mu+a3); rt300@0: */ rt300@0: a0 = wavetableOld[n3] - wavetableOld[n2] - wavetableOld[n0] + wavetableOld[n1]; rt300@0: a1 = wavetableOld[n0] - wavetableOld[n1] - a0; // y0 - y1 - a0; rt300@0: a2 = wavetableOld[n2] - wavetableOld[n0]; // y2 - y0; rt300@0: a3 = wavetableOld[n1]; rt300@0: rt300@0: double oldsample = a0*fracCubed + a1*fracSquared + a2*frac + a3; rt300@0: rt300@0: a0 = wavetableNew[n3] - wavetableNew[n2] - wavetableNew[n0] + wavetableNew[n1]; rt300@0: a1 = wavetableNew[n0] - wavetableNew[n1] - a0; // y0 - y1 - a0; rt300@0: a2 = wavetableNew[n2] - wavetableNew[n0]; // y2 - y0; rt300@0: a3 = wavetableNew[n1]; rt300@0: rt300@0: double newsample = a0*fracCubed + a1*fracSquared + a2*frac + a3; rt300@0: rt300@0: frameInterpolator += framesPerSample; rt300@0: if(frameInterpolator >= 1.0){ rt300@0: frameInterpolator = 1.0; // just stays outputting new rt300@0: } rt300@0: rt300@0: double sample = (1 - frameInterpolator)*oldsample + frameInterpolator*newsample; rt300@0: //cout << sample << endl; rt300@0: // keep within the bounds of acceptability rt300@0: rt300@0: // beef up rt300@0: sample = sample*3.0; rt300@0: rt300@0: if(sample > 0.99){ rt300@0: sample = 0.99; rt300@0: }else if(sample < -0.99){ rt300@0: sample = -0.99; rt300@0: } rt300@0: rt300@0: return sample; rt300@0: rt300@0: } rt300@0: //----------------------------------------------------------------