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@3
|
32
|
rt300@3
|
33 }
|
rt300@3
|
34 void ScanPath::init(){
|
rt300@3
|
35 framesPerSample = ofGetFrameRate()/SAMPLE_RATE;
|
rt300@0
|
36
|
rt300@0
|
37 }
|
rt300@0
|
38 //----------------------------------------------------------------
|
rt300@0
|
39 ScanPath::~ScanPath(){
|
rt300@3
|
40
|
rt300@3
|
41 //VECTORISE
|
rt300@3
|
42
|
rt300@0
|
43 delete [] wavetableNew;
|
rt300@0
|
44 delete [] wavetableOld;
|
rt300@0
|
45 delete [] wavetableUpdate;
|
rt300@0
|
46 cout << "destructed scanpath\n";
|
rt300@0
|
47 }
|
rt300@0
|
48
|
rt300@0
|
49 void ScanPath::clear(){
|
rt300@3
|
50 //VECTORISE
|
rt300@3
|
51 for(vector<Element>::iterator elitr = pathElements.begin(); elitr < pathElements.end(); elitr++){
|
rt300@3
|
52 (*elitr).eLump->removeFromScanPath();
|
rt300@3
|
53 (*elitr).eSpring->removeFromScanPath();
|
rt300@0
|
54 }
|
rt300@3
|
55 pathElements.clear();
|
rt300@0
|
56 numElements = 0;
|
rt300@3
|
57
|
rt300@0
|
58 }
|
rt300@0
|
59 int ScanPath::howManyElements(){
|
rt300@3
|
60 //return pathElements.size();
|
rt300@0
|
61 return numElements;
|
rt300@0
|
62 }
|
rt300@0
|
63 //----------------------------------------------------------------
|
rt300@0
|
64 void ScanPath::inscribe(double ax, double ay){
|
rt300@0
|
65 // look at coordinates, add the closest lump and it's connecting string
|
rt300@0
|
66 // if we're further away from current lump
|
rt300@0
|
67
|
rt300@0
|
68 // check end points of connecting springs, pick closest
|
rt300@3
|
69
|
rt300@3
|
70 // NOW IN MESH
|
rt300@0
|
71 }
|
rt300@0
|
72 void ScanPath::draw(){
|
rt300@0
|
73 // draw the actual waveform in the corner
|
rt300@0
|
74
|
rt300@0
|
75 int width = 768;
|
rt300@0
|
76 int height = 128;
|
rt300@0
|
77 double sampval = 0.0;
|
rt300@0
|
78 int leftsampnum = 0;
|
rt300@0
|
79 int rightsampnum = 0;
|
rt300@0
|
80 float sampscale = 0.0, prevsampscale = 0.0, interp = 0.0;
|
rt300@0
|
81
|
rt300@0
|
82 ofSetColor(0, 0, 0);
|
rt300@0
|
83 double step = double(numElements)/width; // how much we are stepping thru wave per pixel
|
rt300@0
|
84 for(int i = 0; i < width; i++){
|
rt300@0
|
85
|
rt300@0
|
86 leftsampnum = floor(i * step); // basic nearest neighbour interpolation
|
rt300@0
|
87 rightsampnum = ceil(i*step);
|
rt300@0
|
88 interp = (i*step)-leftsampnum;
|
rt300@0
|
89 if(rightsampnum < numElements){
|
rt300@0
|
90 sampval = (1 - interp)*wavetableNew[leftsampnum] + interp*wavetableNew[rightsampnum];
|
rt300@0
|
91 }
|
rt300@0
|
92 sampscale = (sampval * 700) + height/2.0; // centre and scale
|
rt300@0
|
93 ofSetLineWidth(2);
|
rt300@0
|
94 ofLine(sampscale, i, prevsampscale, i-1); // draw a line from pixel to pixel (?)
|
rt300@0
|
95 prevsampscale = sampscale;
|
rt300@0
|
96 }
|
rt300@0
|
97
|
rt300@0
|
98 }
|
rt300@0
|
99 void drawCubic(){
|
rt300@0
|
100
|
rt300@0
|
101 }
|
rt300@0
|
102 //----------------------------------------------------------------
|
rt300@0
|
103 // add spring
|
rt300@0
|
104 void ScanPath::addSpring(){
|
rt300@0
|
105 // see add element
|
rt300@0
|
106 }
|
rt300@0
|
107 //----------------------------------------------------------------
|
rt300@0
|
108 // add lump
|
rt300@0
|
109 void ScanPath::addLump(){
|
rt300@0
|
110 // see add element
|
rt300@0
|
111 }
|
rt300@0
|
112 //----------------------------------------------------------------
|
rt300@0
|
113 // add lump
|
rt300@0
|
114 double ScanPath::getTotalLength(){
|
rt300@0
|
115 // for interesting modulations...
|
rt300@0
|
116 currentLength = 0.0;
|
rt300@3
|
117
|
rt300@3
|
118 for(vector<Element>::iterator elitr = pathElements.begin(); elitr < pathElements.end(); elitr++){
|
rt300@3
|
119
|
rt300@3
|
120 currentLength = (*elitr).eSpring->getLength();
|
rt300@0
|
121 }
|
rt300@0
|
122 return currentLength;
|
rt300@0
|
123
|
rt300@0
|
124 }
|
rt300@0
|
125 //----------------------------------------------------------------
|
rt300@0
|
126 void ScanPath::initWavetables(){
|
rt300@0
|
127 wavetableNew = new double[maxElements];
|
rt300@0
|
128 wavetableOld = new double[maxElements];
|
rt300@0
|
129 wavetableUpdate = new double[maxElements];
|
rt300@0
|
130
|
rt300@0
|
131 for(int i = 0; i < maxElements; i++){
|
rt300@0
|
132 wavetableOld[i] = 0.0;
|
rt300@0
|
133 wavetableNew[i] = 0.0;
|
rt300@0
|
134 wavetableUpdate[i] = 0.0;
|
rt300@0
|
135 }
|
rt300@0
|
136
|
rt300@0
|
137 }
|
rt300@0
|
138 //----------------------------------------------------------------
|
rt300@3
|
139 void ScanPath::addElement(Lump* const aLump, Spring * const aSpring){
|
rt300@0
|
140 // insert ptr to the lump and spring into array
|
rt300@3
|
141
|
rt300@3
|
142
|
rt300@3
|
143 if(numElements + 1 >= maxElements){
|
rt300@3
|
144 cout << " max elements reached!\n";
|
rt300@0
|
145 return;
|
rt300@0
|
146 }
|
rt300@3
|
147
|
rt300@3
|
148 pathElements.push_back(Element(aLump,aSpring));
|
rt300@0
|
149
|
rt300@3
|
150 // maybe do this in mesh?
|
rt300@0
|
151 aLump->addToScanPath();
|
rt300@0
|
152 aSpring->addToScanPath();
|
rt300@3
|
153 numElements++;
|
rt300@0
|
154
|
rt300@3
|
155
|
rt300@0
|
156 }
|
rt300@0
|
157 //----------------------------------------------------------------
|
rt300@0
|
158 void ScanPath::updateWavetables(){
|
rt300@0
|
159 // swap old , new
|
rt300@0
|
160 double * temp;
|
rt300@0
|
161
|
rt300@1
|
162 // TODO THRED MUTEX HERE!??
|
rt300@3
|
163 // this is called from graphics thread
|
rt300@3
|
164 // reset the interp between frames
|
rt300@1
|
165
|
rt300@3
|
166 /*
|
rt300@3
|
167 int i = 0;
|
rt300@3
|
168 while(audioAccessing){
|
rt300@3
|
169 i++;
|
rt300@3
|
170 }
|
rt300@3
|
171 cout << "buffers swapped while update!" << i << "times\n";
|
rt300@3
|
172 updateAccessing = true;
|
rt300@3
|
173
|
rt300@3
|
174 */
|
rt300@0
|
175 switch(scanMode){
|
rt300@0
|
176 case DISPLACEMENT:
|
rt300@0
|
177 // now fill with new values
|
rt300@0
|
178 for(int i = 0; i < numElements; i++){
|
rt300@3
|
179 // double check
|
rt300@3
|
180 if(pathElements[i].eLump->isInScanPath){
|
rt300@3
|
181 wavetableUpdate[i] = pathElements[i].eLump->scanRadialDisplacement()/1.5;
|
rt300@3
|
182 }
|
rt300@0
|
183
|
rt300@0
|
184 }
|
rt300@0
|
185 break;
|
rt300@0
|
186 case SPEED:
|
rt300@0
|
187 for(int i = 0; i < numElements; i++){
|
rt300@3
|
188 if(pathElements[i].eLump->isInScanPath){
|
rt300@3
|
189 wavetableUpdate[i] = pathElements[i].eLump->scanLumpSpeed();
|
rt300@3
|
190 }
|
rt300@0
|
191 }
|
rt300@0
|
192 break;
|
rt300@0
|
193 case SPRING_FORCE:
|
rt300@0
|
194 for(int i = 0; i < numElements; i++){
|
rt300@3
|
195 if(pathElements[i].eSpring->isInScanPath){
|
rt300@3
|
196 wavetableUpdate[i] = pathElements[i].eSpring->getForceMag();
|
rt300@3
|
197 }
|
rt300@0
|
198 }
|
rt300@0
|
199 break;
|
rt300@0
|
200 case YPOS:
|
rt300@0
|
201 for(int i = 0; i < numElements; i++){
|
rt300@3
|
202 if(pathElements[i].eLump->isInScanPath){
|
rt300@3
|
203 wavetableUpdate[i] = pathElements[i].eLump->scanYPos();
|
rt300@3
|
204 }
|
rt300@0
|
205 }
|
rt300@0
|
206 break;
|
rt300@0
|
207 default:
|
rt300@0
|
208 break;
|
rt300@0
|
209
|
rt300@0
|
210
|
rt300@0
|
211 }
|
rt300@1
|
212
|
rt300@3
|
213
|
rt300@3
|
214
|
rt300@0
|
215
|
rt300@0
|
216 temp = wavetableOld;
|
rt300@0
|
217 wavetableOld = wavetableNew;
|
rt300@0
|
218 wavetableNew = wavetableUpdate;
|
rt300@0
|
219 wavetableUpdate = temp;
|
rt300@3
|
220
|
rt300@3
|
221 // END THREAD MUTEX
|
rt300@0
|
222 updateAccessing = false;
|
rt300@0
|
223
|
rt300@0
|
224 frameInterpolator = 0.0;
|
rt300@0
|
225 framesPerSample = 2.0*ofGetFrameRate()/SAMPLE_RATE; // attempt to get a reasonable est. of how fast to interp
|
rt300@0
|
226
|
rt300@0
|
227 }
|
rt300@0
|
228 //----------------------------------------------------------------
|
rt300@3
|
229 //----------------------------------------------------------------
|
rt300@3
|
230 // AUDIO THREAD STUFF
|
rt300@3
|
231 //----------------------------------------------------------------
|
rt300@0
|
232 // get next sample
|
rt300@3
|
233
|
rt300@0
|
234 double ScanPath::getNextSample(double aPhasor){
|
rt300@0
|
235 // move along path, interpolating between points
|
rt300@0
|
236 // move between frames too
|
rt300@0
|
237 double alongPath = aPhasor*double(numElements);
|
rt300@0
|
238
|
rt300@0
|
239 // indexes for interpolated points
|
rt300@0
|
240 int n0 = floor(alongPath);
|
rt300@0
|
241 int n1 = n0+1;
|
rt300@0
|
242 if(n1 >= numElements){
|
rt300@0
|
243 n1 = 0;
|
rt300@0
|
244 }
|
rt300@0
|
245
|
rt300@0
|
246 double frac = alongPath - double(n0);
|
rt300@0
|
247
|
rt300@3
|
248 // TODO THRED MUTEX HERE!??
|
rt300@3
|
249 // this is called from audio thread
|
rt300@3
|
250 /*
|
rt300@3
|
251 int i = 0;
|
rt300@3
|
252 while(updateAccessing){
|
rt300@3
|
253 i++;
|
rt300@3
|
254 }
|
rt300@0
|
255 audioAccessing = true;
|
rt300@3
|
256 cout << "update is accessing while audio is" << i << "times\n";
|
rt300@3
|
257
|
rt300@3
|
258 */
|
rt300@1
|
259
|
rt300@0
|
260 double oldsample = (1 - frac) * wavetableOld[n0] + frac * wavetableOld[n1];
|
rt300@0
|
261
|
rt300@0
|
262 double newsample = (1 - frac) * wavetableNew[n0] + frac * wavetableNew[n1];
|
rt300@0
|
263
|
rt300@1
|
264 // END THREAD MUTEX
|
rt300@0
|
265 audioAccessing = false;
|
rt300@0
|
266
|
rt300@0
|
267 frameInterpolator += framesPerSample;
|
rt300@0
|
268 if(frameInterpolator >= 1.0){
|
rt300@0
|
269 //cout << "frame interp > 1\n";
|
rt300@0
|
270 frameInterpolator = 1.0; // just stays outputting new
|
rt300@0
|
271 }
|
rt300@0
|
272
|
rt300@0
|
273 double sample = (1 - frameInterpolator)*oldsample + frameInterpolator*newsample;
|
rt300@0
|
274 //cout << sample << endl;
|
rt300@0
|
275 // keep within the bounds of acceptability
|
rt300@0
|
276 if(sample > 0.99){
|
rt300@0
|
277 // cout << "OUCH\n";
|
rt300@0
|
278 sample = 0.99;
|
rt300@0
|
279 }else if(sample < -0.99){
|
rt300@0
|
280 sample = -0.99;
|
rt300@0
|
281 }
|
rt300@0
|
282 return sample;
|
rt300@0
|
283
|
rt300@0
|
284 }
|
rt300@0
|
285 //----------------------------------------------------------------
|
rt300@0
|
286 // get next sample
|
rt300@0
|
287 double ScanPath::getNextSample(){
|
rt300@0
|
288 // move along wavetable, no interpolation ie: length of path is pitch
|
rt300@0
|
289 static int n = 0;
|
rt300@0
|
290 double oldsample = wavetableOld[n];
|
rt300@0
|
291
|
rt300@0
|
292 double newsample = wavetableNew[n];
|
rt300@0
|
293 n++;
|
rt300@0
|
294 if (n >= numElements){
|
rt300@0
|
295 n = 0;
|
rt300@0
|
296 }
|
rt300@0
|
297
|
rt300@0
|
298 frameInterpolator += framesPerSample;
|
rt300@0
|
299 if(frameInterpolator >= 1.0){
|
rt300@0
|
300 //cout << "frame interp > 1\n";
|
rt300@0
|
301 frameInterpolator = 1.0; // just stays outputting new
|
rt300@0
|
302 }
|
rt300@0
|
303
|
rt300@0
|
304 double sample = (1 - frameInterpolator)*oldsample + frameInterpolator*newsample;
|
rt300@0
|
305 return sample*3.0;
|
rt300@0
|
306
|
rt300@0
|
307 }
|
rt300@0
|
308 //----------------------------------------------------------------
|
rt300@0
|
309 //----------------------------------------------------------------
|
rt300@0
|
310 // get next sample with cubic interpolation
|
rt300@0
|
311 double ScanPath::getNextSampleCubic(double aPhasor){
|
rt300@0
|
312 // move along path, interpolating between points
|
rt300@0
|
313 // move between frames too
|
rt300@0
|
314 double alongPath = aPhasor*double(numElements);
|
rt300@0
|
315
|
rt300@0
|
316 // indexes for interpolated points
|
rt300@0
|
317 int n1 = floor(alongPath);
|
rt300@0
|
318
|
rt300@0
|
319 int n0 = n1-1;
|
rt300@0
|
320 if(n0 < 0){
|
rt300@0
|
321 n0 = numElements;
|
rt300@0
|
322 }
|
rt300@0
|
323 int n2 = n1+1;
|
rt300@0
|
324 if(n2 >= numElements){
|
rt300@0
|
325 n2 = 0;
|
rt300@0
|
326 }
|
rt300@0
|
327 int n3 = n2+1;
|
rt300@0
|
328 if(n3 >= numElements){
|
rt300@0
|
329 n3 = 0;
|
rt300@0
|
330 }
|
rt300@0
|
331 double frac = alongPath - double(n0);
|
rt300@0
|
332 double fracSquared = frac * frac;
|
rt300@0
|
333 double fracCubed = fracSquared * frac;
|
rt300@0
|
334 double a0,a1,a2,a3;
|
rt300@0
|
335 //cout << n0 << endl;
|
rt300@0
|
336 // cubic interp
|
rt300@0
|
337 /*
|
rt300@0
|
338 double y0,double y1,
|
rt300@0
|
339 double y2,double y3,
|
rt300@0
|
340 double mu)
|
rt300@0
|
341 {
|
rt300@0
|
342 double a0,a1,a2,a3,mu2;
|
rt300@0
|
343
|
rt300@0
|
344 mu2 = mu*mu;
|
rt300@0
|
345 a0 = y3 - y2 - y0 + y1;
|
rt300@0
|
346 a1 = y0 - y1 - a0;
|
rt300@0
|
347 a2 = y2 - y0;
|
rt300@0
|
348 a3 = y1;
|
rt300@0
|
349
|
rt300@0
|
350 return(a0*mu*mu2+a1*mu2+a2*mu+a3);
|
rt300@0
|
351 */
|
rt300@0
|
352 a0 = wavetableOld[n3] - wavetableOld[n2] - wavetableOld[n0] + wavetableOld[n1];
|
rt300@0
|
353 a1 = wavetableOld[n0] - wavetableOld[n1] - a0; // y0 - y1 - a0;
|
rt300@0
|
354 a2 = wavetableOld[n2] - wavetableOld[n0]; // y2 - y0;
|
rt300@0
|
355 a3 = wavetableOld[n1];
|
rt300@0
|
356
|
rt300@0
|
357 double oldsample = a0*fracCubed + a1*fracSquared + a2*frac + a3;
|
rt300@0
|
358
|
rt300@0
|
359 a0 = wavetableNew[n3] - wavetableNew[n2] - wavetableNew[n0] + wavetableNew[n1];
|
rt300@0
|
360 a1 = wavetableNew[n0] - wavetableNew[n1] - a0; // y0 - y1 - a0;
|
rt300@0
|
361 a2 = wavetableNew[n2] - wavetableNew[n0]; // y2 - y0;
|
rt300@0
|
362 a3 = wavetableNew[n1];
|
rt300@0
|
363
|
rt300@0
|
364 double newsample = a0*fracCubed + a1*fracSquared + a2*frac + a3;
|
rt300@0
|
365
|
rt300@0
|
366 frameInterpolator += framesPerSample;
|
rt300@0
|
367 if(frameInterpolator >= 1.0){
|
rt300@0
|
368 frameInterpolator = 1.0; // just stays outputting new
|
rt300@0
|
369 }
|
rt300@0
|
370
|
rt300@0
|
371 double sample = (1 - frameInterpolator)*oldsample + frameInterpolator*newsample;
|
rt300@0
|
372 //cout << sample << endl;
|
rt300@0
|
373 // keep within the bounds of acceptability
|
rt300@0
|
374
|
rt300@0
|
375 // beef up
|
rt300@0
|
376 sample = sample*3.0;
|
rt300@0
|
377
|
rt300@0
|
378 if(sample > 0.99){
|
rt300@0
|
379 sample = 0.99;
|
rt300@0
|
380 }else if(sample < -0.99){
|
rt300@0
|
381 sample = -0.99;
|
rt300@0
|
382 }
|
rt300@0
|
383
|
rt300@0
|
384 return sample;
|
rt300@0
|
385
|
rt300@0
|
386 }
|
rt300@0
|
387 //---------------------------------------------------------------- |