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@0
|
83 ofSetColor(0, 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@0
|
159 void ScanPath::updateWavetables(){
|
rt300@0
|
160 // swap old , new
|
rt300@0
|
161 double * temp;
|
rt300@5
|
162 if(pathElements.size() == 0) return;
|
rt300@1
|
163 // TODO THRED MUTEX HERE!??
|
rt300@3
|
164 // this is called from graphics thread
|
rt300@3
|
165 // reset the interp between frames
|
rt300@5
|
166 /*
|
rt300@3
|
167 int i = 0;
|
rt300@3
|
168 while(audioAccessing){
|
rt300@3
|
169 i++;
|
rt300@3
|
170 }
|
rt300@4
|
171 if(i > 0){
|
rt300@4
|
172 cout << "Update wavetables had to wait for audio access " << i << " times\n";
|
rt300@4
|
173 // hardly ever happens
|
rt300@4
|
174 }
|
rt300@5
|
175 */
|
rt300@3
|
176 updateAccessing = true;
|
rt300@3
|
177
|
rt300@4
|
178
|
rt300@0
|
179 switch(scanMode){
|
rt300@0
|
180 case DISPLACEMENT:
|
rt300@0
|
181 // now fill with new values
|
rt300@0
|
182 for(int i = 0; i < numElements; i++){
|
rt300@3
|
183 // double check
|
rt300@5
|
184
|
rt300@5
|
185 wavetableUpdate[i] = pathElements[i].eLump->scanRadialDisplacement();
|
rt300@5
|
186
|
rt300@0
|
187
|
rt300@0
|
188 }
|
rt300@0
|
189 break;
|
rt300@0
|
190 case SPEED:
|
rt300@0
|
191 for(int i = 0; i < numElements; i++){
|
rt300@5
|
192
|
rt300@5
|
193 wavetableUpdate[i] = pathElements[i].eLump->scanLumpSpeed();
|
rt300@5
|
194
|
rt300@0
|
195 }
|
rt300@0
|
196 break;
|
rt300@0
|
197 case SPRING_FORCE:
|
rt300@0
|
198 for(int i = 0; i < numElements; i++){
|
rt300@3
|
199 if(pathElements[i].eSpring->isInScanPath){
|
rt300@3
|
200 wavetableUpdate[i] = pathElements[i].eSpring->getForceMag();
|
rt300@3
|
201 }
|
rt300@0
|
202 }
|
rt300@0
|
203 break;
|
rt300@0
|
204 case YPOS:
|
rt300@0
|
205 for(int i = 0; i < numElements; i++){
|
rt300@3
|
206 if(pathElements[i].eLump->isInScanPath){
|
rt300@3
|
207 wavetableUpdate[i] = pathElements[i].eLump->scanYPos();
|
rt300@3
|
208 }
|
rt300@0
|
209 }
|
rt300@0
|
210 break;
|
rt300@0
|
211 default:
|
rt300@0
|
212 break;
|
rt300@4
|
213
|
rt300@0
|
214 }
|
rt300@4
|
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@5
|
237 if(pathElements.size() == 0) return 0.0;
|
rt300@5
|
238
|
rt300@0
|
239 double alongPath = aPhasor*double(numElements);
|
rt300@0
|
240
|
rt300@0
|
241 // indexes for interpolated points
|
rt300@0
|
242 int n0 = floor(alongPath);
|
rt300@0
|
243 int n1 = n0+1;
|
rt300@0
|
244 if(n1 >= numElements){
|
rt300@0
|
245 n1 = 0;
|
rt300@0
|
246 }
|
rt300@0
|
247
|
rt300@0
|
248 double frac = alongPath - double(n0);
|
rt300@0
|
249
|
rt300@3
|
250 // TODO THRED MUTEX HERE!??
|
rt300@3
|
251 // this is called from audio thread
|
rt300@5
|
252 /*
|
rt300@3
|
253 int i = 0;
|
rt300@3
|
254 while(updateAccessing){
|
rt300@3
|
255 i++;
|
rt300@3
|
256 }
|
rt300@5
|
257 */
|
rt300@0
|
258 audioAccessing = true;
|
rt300@5
|
259 // if(i>0) cout << "Audio thread had to wait for wavetable update " << i << " times\n";
|
rt300@4
|
260
|
rt300@1
|
261
|
rt300@0
|
262 double oldsample = (1 - frac) * wavetableOld[n0] + frac * wavetableOld[n1];
|
rt300@0
|
263
|
rt300@0
|
264 double newsample = (1 - frac) * wavetableNew[n0] + frac * wavetableNew[n1];
|
rt300@0
|
265
|
rt300@1
|
266 // END THREAD MUTEX
|
rt300@0
|
267 audioAccessing = false;
|
rt300@0
|
268
|
rt300@0
|
269 frameInterpolator += framesPerSample;
|
rt300@0
|
270 if(frameInterpolator >= 1.0){
|
rt300@0
|
271 //cout << "frame interp > 1\n";
|
rt300@0
|
272 frameInterpolator = 1.0; // just stays outputting new
|
rt300@0
|
273 }
|
rt300@0
|
274
|
rt300@0
|
275 double sample = (1 - frameInterpolator)*oldsample + frameInterpolator*newsample;
|
rt300@0
|
276 //cout << sample << endl;
|
rt300@0
|
277 // keep within the bounds of acceptability
|
rt300@0
|
278 if(sample > 0.99){
|
rt300@0
|
279 // cout << "OUCH\n";
|
rt300@0
|
280 sample = 0.99;
|
rt300@0
|
281 }else if(sample < -0.99){
|
rt300@0
|
282 sample = -0.99;
|
rt300@0
|
283 }
|
rt300@0
|
284 return sample;
|
rt300@0
|
285
|
rt300@0
|
286 }
|
rt300@0
|
287 //----------------------------------------------------------------
|
rt300@0
|
288 // get next sample
|
rt300@0
|
289 double ScanPath::getNextSample(){
|
rt300@0
|
290 // move along wavetable, no interpolation ie: length of path is pitch
|
rt300@0
|
291 static int n = 0;
|
rt300@0
|
292 double oldsample = wavetableOld[n];
|
rt300@0
|
293
|
rt300@0
|
294 double newsample = wavetableNew[n];
|
rt300@0
|
295 n++;
|
rt300@0
|
296 if (n >= numElements){
|
rt300@0
|
297 n = 0;
|
rt300@0
|
298 }
|
rt300@0
|
299
|
rt300@0
|
300 frameInterpolator += framesPerSample;
|
rt300@0
|
301 if(frameInterpolator >= 1.0){
|
rt300@0
|
302 //cout << "frame interp > 1\n";
|
rt300@0
|
303 frameInterpolator = 1.0; // just stays outputting new
|
rt300@0
|
304 }
|
rt300@0
|
305
|
rt300@0
|
306 double sample = (1 - frameInterpolator)*oldsample + frameInterpolator*newsample;
|
rt300@0
|
307 return sample*3.0;
|
rt300@0
|
308
|
rt300@0
|
309 }
|
rt300@0
|
310 //----------------------------------------------------------------
|
rt300@0
|
311 //----------------------------------------------------------------
|
rt300@0
|
312 // get next sample with cubic interpolation
|
rt300@0
|
313 double ScanPath::getNextSampleCubic(double aPhasor){
|
rt300@0
|
314 // move along path, interpolating between points
|
rt300@0
|
315 // move between frames too
|
rt300@0
|
316 double alongPath = aPhasor*double(numElements);
|
rt300@0
|
317
|
rt300@0
|
318 // indexes for interpolated points
|
rt300@0
|
319 int n1 = floor(alongPath);
|
rt300@0
|
320
|
rt300@0
|
321 int n0 = n1-1;
|
rt300@0
|
322 if(n0 < 0){
|
rt300@0
|
323 n0 = numElements;
|
rt300@0
|
324 }
|
rt300@0
|
325 int n2 = n1+1;
|
rt300@0
|
326 if(n2 >= numElements){
|
rt300@0
|
327 n2 = 0;
|
rt300@0
|
328 }
|
rt300@0
|
329 int n3 = n2+1;
|
rt300@0
|
330 if(n3 >= numElements){
|
rt300@0
|
331 n3 = 0;
|
rt300@0
|
332 }
|
rt300@0
|
333 double frac = alongPath - double(n0);
|
rt300@0
|
334 double fracSquared = frac * frac;
|
rt300@0
|
335 double fracCubed = fracSquared * frac;
|
rt300@0
|
336 double a0,a1,a2,a3;
|
rt300@0
|
337 //cout << n0 << endl;
|
rt300@0
|
338 // cubic interp
|
rt300@0
|
339 /*
|
rt300@0
|
340 double y0,double y1,
|
rt300@0
|
341 double y2,double y3,
|
rt300@0
|
342 double mu)
|
rt300@0
|
343 {
|
rt300@0
|
344 double a0,a1,a2,a3,mu2;
|
rt300@0
|
345
|
rt300@0
|
346 mu2 = mu*mu;
|
rt300@0
|
347 a0 = y3 - y2 - y0 + y1;
|
rt300@0
|
348 a1 = y0 - y1 - a0;
|
rt300@0
|
349 a2 = y2 - y0;
|
rt300@0
|
350 a3 = y1;
|
rt300@0
|
351
|
rt300@0
|
352 return(a0*mu*mu2+a1*mu2+a2*mu+a3);
|
rt300@0
|
353 */
|
rt300@0
|
354 a0 = wavetableOld[n3] - wavetableOld[n2] - wavetableOld[n0] + wavetableOld[n1];
|
rt300@0
|
355 a1 = wavetableOld[n0] - wavetableOld[n1] - a0; // y0 - y1 - a0;
|
rt300@0
|
356 a2 = wavetableOld[n2] - wavetableOld[n0]; // y2 - y0;
|
rt300@0
|
357 a3 = wavetableOld[n1];
|
rt300@0
|
358
|
rt300@0
|
359 double oldsample = a0*fracCubed + a1*fracSquared + a2*frac + a3;
|
rt300@0
|
360
|
rt300@0
|
361 a0 = wavetableNew[n3] - wavetableNew[n2] - wavetableNew[n0] + wavetableNew[n1];
|
rt300@0
|
362 a1 = wavetableNew[n0] - wavetableNew[n1] - a0; // y0 - y1 - a0;
|
rt300@0
|
363 a2 = wavetableNew[n2] - wavetableNew[n0]; // y2 - y0;
|
rt300@0
|
364 a3 = wavetableNew[n1];
|
rt300@0
|
365
|
rt300@0
|
366 double newsample = a0*fracCubed + a1*fracSquared + a2*frac + a3;
|
rt300@0
|
367
|
rt300@0
|
368 frameInterpolator += framesPerSample;
|
rt300@0
|
369 if(frameInterpolator >= 1.0){
|
rt300@0
|
370 frameInterpolator = 1.0; // just stays outputting new
|
rt300@0
|
371 }
|
rt300@0
|
372
|
rt300@0
|
373 double sample = (1 - frameInterpolator)*oldsample + frameInterpolator*newsample;
|
rt300@0
|
374 //cout << sample << endl;
|
rt300@0
|
375 // keep within the bounds of acceptability
|
rt300@0
|
376
|
rt300@0
|
377 // beef up
|
rt300@0
|
378 sample = sample*3.0;
|
rt300@0
|
379
|
rt300@0
|
380 if(sample > 0.99){
|
rt300@0
|
381 sample = 0.99;
|
rt300@0
|
382 }else if(sample < -0.99){
|
rt300@0
|
383 sample = -0.99;
|
rt300@0
|
384 }
|
rt300@0
|
385
|
rt300@0
|
386 return sample;
|
rt300@0
|
387
|
rt300@0
|
388 }
|
rt300@0
|
389 //---------------------------------------------------------------- |