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