CSL 5.2

- Main Page
- Related Pages
- Modules
- Namespaces
- Classes
- Files

- File List
- File Members

ShoeBox.cpp
Go to the documentation of this file.
1 //
2 // ShoeBox.m
3 // ShoeBox
4 //
5 // Created by Jorge Castellanos & Will Wolcott on 4/29/05.
6 // Copyright 2005 Jorge Castellanos & Will Wolcott. All rights reserved.
7 //
8
9
10 // IMPORTANT NOTES:
11 // 6) WRITE ALL INITIALIZERS NEEDED
12 // 7) WE MUST CHECK (IN THE INIT) THAT LISTENER AND SOURCE ARE ACTUALLY INSIDE THE ROOM.
13
14
15 #include "ShoeBox.h"
16
17 #include "CSL_Core.h"
18
19 const float kWoodCoefficient = 0.85; // 1/4" Plywood
20 const float kMarbleCoefficient = 0.99;
21 const float kConcreteCoefficient = 0.98;
22 const float kBrockCoefficient = 0.97;
23 const float kGlassCoefficient = 0.96;
24
25 #define SPEED_OF_SOUND 0.341
26
27 using namespace csl;
28
29 // This will be one of the many constructors to set up the object.
30
31 ShoeBox::ShoeBox() : mRoomSize(3, 4, 3), mSource(1, 2, 1), mListenerPosition(1.5, 2., 1.) {
32
33 mDampX = kBrockCoefficient;
34 mDampY = kBrockCoefficient;
35 mDampZ = kBrockCoefficient;
36
37 mDuration = 50;
38
39
40 }
41
42 ShoeBox::~ShoeBox() {
43
44
45 }
46
47 void ShoeBox::setWallMaterialsDamp(int dampX, int dampY, int dampZ) {
48
49 switch(dampX) {
50 case kMarble:
51 mDampX = kMarbleCoefficient;
52 break;
53 case kConcrete:
54 mDampX = kConcreteCoefficient;
55 break;
56 case kBrick:
57 mDampX = kBrockCoefficient;
58 break;
59 case kGlass:
60 mDampX = kGlassCoefficient;
61 break;
62 case kWood:
63 mDampX = kWoodCoefficient;
64 break;
65 }
66 switch(dampY) {
67 case kMarble:
68 mDampY = kMarbleCoefficient;
69 break;
70 case kConcrete:
71 mDampY = kConcreteCoefficient;
72 break;
73 case kBrick:
74 mDampY = kBrockCoefficient;
75 break;
76 case kGlass:
77 mDampY = kGlassCoefficient;
78 break;
79 case kWood:
80 mDampY = kWoodCoefficient;
81 break;
82 }
83 switch(dampZ) {
84 case kMarble:
85 mDampZ = kMarbleCoefficient;
86 break;
87 case kConcrete:
88 mDampZ = kConcreteCoefficient;
89 break;
90 case kBrick:
91 mDampZ = kBrockCoefficient;
92 break;
93 case kGlass:
94 mDampZ = kGlassCoefficient;
95 break;
96 case kWood:
97 mDampZ = kWoodCoefficient;
98 break;
99 }
100
101 }
102
103 void ShoeBox::setSourceLocation(float x, float y, float z) {
104
105 mSource.x = x;
106 mSource.y = y;
107 mSource.z = z;
108
109 logMsg("setSourceCalled: X = %g, Y = %g, Z = %g", mSource.x, mSource.y, mSource.z);
110
111 checkPositionValues();
112 }
113
114 void ShoeBox::setListenerLocation(float x, float y, float z) {
115
116 mListenerPosition.x = x;
117 mListenerPosition.y = y;
118 mListenerPosition.z = z;
119
120 checkPositionValues();
121 }
122
123 void ShoeBox::setRoomSize(float x, float y, float z) {
124
125 mRoomSize.x = x;
126 mRoomSize.y = y;
127 mRoomSize.z = z;
128
129 checkPositionValues();
130 }
131
132 bool ShoeBox::checkPositionValues() {
133
134 if(mRoomSize.x < mListenerPosition.x || mRoomSize.x < mSource.x)
135 return 1;
136 if(mRoomSize.y < mListenerPosition.y || mRoomSize.y < mSource.y)
137 return 1;
138 if(mRoomSize.z < mListenerPosition.z || mRoomSize.z < mSource.z)
139 return 1;
140
141 return 0;
142 }
143
144 void ShoeBox::shellSort() {
145 int i, j, increment;
146 float temp, pairTemp, anglesTemp;
147
148 increment = 3;
149 while (increment > 0)
150 {
151 for (i=0; i < mNumReflections; i++)
152 {
153 j = i;
154 temp = mReflectionsArray[i];
155 pairTemp = mGainsArray[i];
156 anglesTemp = mAnglesArray[i];
157 while ((j >= increment) && (mReflectionsArray[j-increment] > temp)) {
158 mReflectionsArray[j] = mReflectionsArray[j - increment];
159 mGainsArray[j] = mGainsArray[j - increment];
160 mAnglesArray[j] = mAnglesArray[j - increment];
161 j = j - increment;
162 }
163 mReflectionsArray[j] = temp;
164 mGainsArray[j] = pairTemp;
165 mAnglesArray[j] = anglesTemp;
166 }
167
168 if (increment/2 != 0)
169 increment = increment/2;
170 else if (increment == 1)
171 increment = 0;
172 else
173 increment = 1;
174 }
175
176 }
177
178
179 void ShoeBox::setDuration(int ms) { mDuration = ms; }
180
181
182 void ShoeBox::findNumReflectionsFromTime() {
183
184 // VERY FAST AND UGLY HACK TO NOT OVER CALCULATE REFLECTIONS. WE'LL NEED TO ADD A TIMETOREF FUNCT.
185 mDuration = (mRoomSize.x + mRoomSize.y + mRoomSize.z) * 3;
186 // 0.341 is the speed of sound in mm/s @ 20 Celsius
187 float clippingRadius = SPEED_OF_SOUND * mDuration; // clippingRadius is the maximum ray length to be traced.
188 mMaxBouncesX = (int)ceil(clippingRadius / (mRoomSize.x));
189 mMaxBouncesY = (int)ceil(clippingRadius / (mRoomSize.y));
190 mMaxBouncesZ = (int)ceil(clippingRadius / (mRoomSize.z));
191
192 mNumReflections = mMaxBouncesX * mMaxBouncesY * mMaxBouncesZ * 8;
193
194 if(mReflectionsArray != NULL)
195 free (mReflectionsArray);
196 if(mGainsArray != NULL)
197 free (mGainsArray);
198 if(mAnglesArray != NULL)
199 free (mAnglesArray);
200
201 mReflectionsArray = (float *)calloc(mNumReflections, sizeof(float)); // Allocating twice, because we are also storing the gain.
202 mGainsArray = (float *)calloc(mNumReflections, sizeof(float));
203 mAnglesArray = (float *)calloc(mNumReflections, sizeof(float));
204 if(mReflectionsArray && mGainsArray && mAnglesArray)
205 logMsg("Allocated memory for the reflections and gains. Total %d bytes", mNumReflections);
206
207 logMsg("Reflection time = %d, bounces = %d, %d, %d", mDuration, mMaxBouncesX, mMaxBouncesY, mMaxBouncesZ);
208
209 }
210
211 void ShoeBox::calculateReflections() {
212
213 // Called in here because memory needs to be allocated accordingly to the sizes and reflection time requested.
214 findNumReflectionsFromTime();
215
216 float imageX[mMaxBouncesX],imageY[mMaxBouncesY],imageZ[mMaxBouncesZ];
217 float powOfXDelta, powOfMiusXDelta, powOfYDelta, powOfMiusYDelta, powOfZDelta, powOfMiusZDelta;
218 float distanceFromSource, initalDistance, initialDelay, reflections;
219 float reflectionAngleI, reflectionAngleII, reflectionAngleIII, reflectionAngleIV;
220 int reflXpos,reflXneg,reflYpos,reflYneg,reflZpos,reflZneg;
221 int i, j, k;
222
223 initalDistance = sqrt((mSource.x - mListenerPosition.x)*(mSource.x - mListenerPosition.x) + (mSource.y - mListenerPosition.y)*(mSource.y - mListenerPosition.y) + (mSource.z - mListenerPosition.z)*(mSource.z - mListenerPosition.z));
224 initialDelay = initalDistance / SPEED_OF_SOUND;
225
226 // setting the first (real) room coordinates. It's done outside the loop to avoid a phantom double calculation.
227 imageX[0] = mSource.x;
228 imageY[0] = mSource.y;
229 imageZ[0] = mSource.z;
230
231 // We are pre-calculating the COORDINATES for all the image (virtual) sources
232 // as the real room is set above, we'll start with [1] (meaning room two.
233 for(i = 1; i < mMaxBouncesX; i+= 2)
234 imageX[i] = (mRoomSize.x * (i+ 1)) - mSource.x; // Even rooms
235
236 for(i = 2; i < mMaxBouncesX; i+= 2)
237 imageX[i] = (mRoomSize.x * i) + mSource.x; // Odd rooms
238
239 for(i = 1; i < mMaxBouncesY; i+= 2)
240 imageY[i] = (mRoomSize.y * (i+ 1)) - mSource.y;
241
242 for(i = 2; i < mMaxBouncesY; i+= 2)
243 imageY[i] = (mRoomSize.y * i) + mSource.y;
244
245 for(i = 1; i < mMaxBouncesZ; i+= 2)
246 imageZ[i] = (mRoomSize.z * (i+ 1)) - mSource.z;
247
248 for(i = 2; i < mMaxBouncesZ; i+= 2)
249 imageZ[i] = (mRoomSize.z * i) + mSource.z;
250
251
252 // Here is where we calculate the distance from the source to the listener.
253 // we are doing four rooms at a time: even, odd, negativeEven, negativeOdd
254 // this way we don't need to calculate the negative values, just reusing the already caluculated.
255 for(i = 0; i < mMaxBouncesX; i++) {
256 powOfXDelta = (imageX[i] - mListenerPosition.x)*(imageX[i] - mListenerPosition.x);
257 reflXpos = (int)floor(imageX[i]/mRoomSize.x);
258 powOfMiusXDelta = (imageX[i] + mListenerPosition.x)*(imageX[i] + mListenerPosition.x);
259 reflXneg = abs((int)floor(-imageX[i]/mRoomSize.x));
260 for(j = 0; j < mMaxBouncesY; j++) {
261 powOfYDelta = (imageY[j] - mListenerPosition.y)*(imageY[j] - mListenerPosition.y);
262 reflYpos = (int)floor(imageY[j]/mRoomSize.y);
263 powOfMiusYDelta = (imageY[j] + mListenerPosition.y)*(imageY[j] + mListenerPosition.y);
264 reflYneg = abs((int)floor(-imageY[j]/mRoomSize.y));
265 reflectionAngleI = atan2((imageY[j] - mListenerPosition.y),(imageX[i] - mListenerPosition.x));
266 reflectionAngleII = atan2((imageY[j] - mListenerPosition.y),(-imageX[i] - mListenerPosition.x));
267 reflectionAngleIII = atan2((-imageY[j] - mListenerPosition.y),(-imageX[i] - mListenerPosition.x));
268 reflectionAngleIV = atan2((-imageY[j] - mListenerPosition.y),(imageX[i] - mListenerPosition.x));
269 for(k = 0; k < mMaxBouncesZ; k++) {
270 powOfZDelta = (imageZ[k] - mListenerPosition.z)*(imageZ[k] - mListenerPosition.z);
271 reflZpos = (int)floor(imageZ[k]/mRoomSize.z);
272 powOfMiusZDelta = (imageZ[k] + mListenerPosition.z)*(imageZ[k] + mListenerPosition.z);
273 reflZneg = abs((int)floor(-imageZ[k]/mRoomSize.z));
274
275 // calculating x, y, z, positive
276 reflections = pow(mDampX,reflXpos) * pow(mDampY,reflYpos) * pow(mDampZ,reflZpos);
277 distanceFromSource = sqrt(powOfXDelta + powOfYDelta + powOfZDelta);
278 *mReflectionsArray++ = (distanceFromSource / SPEED_OF_SOUND) - initialDelay;
279 *mGainsArray++ = reflections * initalDistance / distanceFromSource;
280 *mAnglesArray++ = reflectionAngleI;
281 // NSLog(@"Reflections %d", reflections );
282
283 // calculating x negative, y, z positive
284 reflections = pow(mDampX,reflXneg) * pow(mDampY,reflYpos) * pow(mDampZ,reflZpos);
285 distanceFromSource = sqrt(powOfMiusXDelta + powOfYDelta + powOfZDelta);
286 *mReflectionsArray++ = (distanceFromSource / SPEED_OF_SOUND) - initialDelay;
287 *mGainsArray++ = reflections * initalDistance / distanceFromSource;
288 *mAnglesArray++ = reflectionAngleII;
289 // NSLog(@"Reflections %d", reflections );
290
291 // calculating x positive, y negative, z positive
292 reflections = pow(mDampX,reflXpos) * pow(mDampY,reflYneg) * pow(mDampZ,reflZpos);
293 distanceFromSource = sqrt(powOfXDelta + powOfMiusYDelta + powOfZDelta);
294 *mReflectionsArray++ = (distanceFromSource / SPEED_OF_SOUND) - initialDelay;
295 *mGainsArray++ = reflections * initalDistance / distanceFromSource;
296 *mAnglesArray++ = reflectionAngleIV;
297 // NSLog(@"Reflections %d", reflections );
298
299 // calculating x, y negative, z positive
300 reflections = pow(mDampX,reflXneg) * pow(mDampY,reflYneg) * pow(mDampZ,reflZpos);
301 distanceFromSource = sqrt(powOfMiusXDelta + powOfMiusYDelta + powOfZDelta);
302 *mReflectionsArray++ = (distanceFromSource / SPEED_OF_SOUND) - initialDelay;
303 *mGainsArray++ = reflections * initalDistance / distanceFromSource;
304 *mAnglesArray++ = reflectionAngleIII;
305 // NSLog(@"Reflections %d", reflections );
306
307 // calculating x, y positive, z negative
308 reflections = pow(mDampX,reflXpos) * pow(mDampY,reflYpos) * pow(mDampZ,reflZneg);
309 distanceFromSource = sqrt(powOfXDelta + powOfYDelta + powOfMiusZDelta);
310 *mReflectionsArray++ = (distanceFromSource / SPEED_OF_SOUND) - initialDelay;
311 *mGainsArray++ = reflections * initalDistance / distanceFromSource;
312 *mAnglesArray++ = reflectionAngleI;
313 // NSLog(@"Reflections %d", reflections );
314
315 // calculating x negative, y positive, z negative
316 reflections = pow(mDampX,reflXneg) * pow(mDampY,reflYpos) * pow(mDampZ,reflZneg);
317 distanceFromSource = sqrt(powOfMiusXDelta + powOfYDelta + powOfMiusZDelta);
318 *mReflectionsArray++ = (distanceFromSource / SPEED_OF_SOUND) - initialDelay;
319 *mGainsArray++ = reflections * initalDistance / distanceFromSource;
320 *mAnglesArray++ = reflectionAngleII;
321 // NSLog(@"Reflections %d", reflections );
322
323 // calculating x positive, y, z negative
324 reflections = pow(mDampX,reflXpos) * pow(mDampY,reflYneg) * pow(mDampZ,reflZneg);
325 distanceFromSource = sqrt(powOfXDelta + powOfMiusYDelta + powOfMiusZDelta);
326 *mReflectionsArray++ = (distanceFromSource / SPEED_OF_SOUND) - initialDelay;
327 *mGainsArray++ = reflections * initalDistance / distanceFromSource;
328 *mAnglesArray++ = reflectionAngleIV;
329 // NSLog(@"Reflections %d", reflections );
330
331 // calculating x, y, z negative
332 reflections = pow(mDampX,reflXneg) * pow(mDampY,reflYneg) * pow(mDampZ,reflZneg);
333 distanceFromSource = sqrt(powOfMiusXDelta + powOfMiusYDelta + powOfMiusZDelta);
334 *mReflectionsArray++ = (distanceFromSource / SPEED_OF_SOUND) - initialDelay;
335 *mGainsArray++ = reflections * initalDistance / distanceFromSource;
336 *mAnglesArray++ = reflectionAngleIII;
337 // NSLog(@"Reflections %d", reflections );
338
339 // NSLog(@"%g, %g, Number of Reflections:%i", timeFromSource, gain, reflections);
340
341 }
342 }
343 }
344
345 // We need to reset the pointers to the original address.
346 mReflectionsArray -= mNumReflections;
347 mGainsArray -= mNumReflections;
348 mAnglesArray -= mNumReflections;
349
350 shellSort();
351
352 for(i = 0; i < mNumReflections; i++)
353 logMsg("Reflection #%d, after %g s & gain of %g angle is: %g", i, mReflectionsArray[i], mGainsArray[i], (mAnglesArray[i] * 180)/3.14159 );
354
355 }
356
357 void ShoeBox::getReflections(float *ref, float *gains, float *angles, int num) {
358 // write if statement that returns a non zero value if there are less reflections than requested.
359 memcpy(ref, mReflectionsArray, num * sizeof(float));
360 memcpy(gains, mGainsArray, num * sizeof(float));
361 memcpy(angles, mAnglesArray, num * sizeof(float));
362 }
363