Jamoma API  0.6.0.a19
Room.cpp
1 // Room.cpp
2 /***************************************************/
3 /*! \class Room
4  \brief Room class
5 
6  This class implements a room, composed of 4 walls, a ceiling
7  and a floor, as well as a sound source and reflections.
8 
9  based on code by Jonas Braasch,
10  adapted by Tristan Matthews, Nils Peters, 2007-2008.
11  */
12 /***************************************************/
13 
14 #include "Room.h"
15 #include "Source.h"
16 #include "MicArray.h"
17 #include "HiMidLow.h"
18 #include "LowPass.h"
19 #include "Mirror.h"
20 #include "Mic.h"
21 #include "Properties.h"
22 
23 #include "ext.h"
24 #include <vector>
25 
26 extern bool globWarningFlag;
27 extern bool globReportFlag;
28 
29 Room::Room(double newWidth, double newDepth, double newHeight, short numChannels, short numSources, short newReflOrder) :
30  width_(newWidth),
31  depth_(newDepth),
32  height_(newHeight),
33  numMics_(numChannels),
34  reflOrder_(newReflOrder),
35  mirrorFlag_(true),
36  filtersPerMic_(reflOrder_ * Properties::NUMWALLS),
37  mics(MicArray(numMics_))
38 {
39  short numRefls;
40 
41  /*
42  According to the image Model the number of Reflections can be determined based on the Reflection Order
43  that is how many times a ray is allowed to hit a wall.
44  */
45  if (reflOrder_ < 0 || reflOrder_ > 3)
46  {
47  post("Invalid reflection order, defaulting to 2.");
48  reflOrder_ = 2;
49  }
50  numRefls = Properties::REFLECTIONS_PER_REFLECTION_ORDER[reflOrder_];
51 
52  mirrors = new Mirror[numRefls];
53 
54  // initialize mirrors with correct order
55  for (int i = 0; i < numRefls; i++)
56  {
57  if (i == Properties::DIRECT) // direct
58  mirrors[i].order(0);
59  else if (i <= Properties::NUMWALLS) // first order refls.
60  mirrors[i].order(1);
61  else // 2nd order
62  mirrors[i].order(2);
63  }
64  // sound source
65  sources = new Source(*this, mirrors);
66 
67  filtersPerMic_ = (reflOrder_ * Properties::NUMWALLS);
68 
69  if (reflOrder_ > 0) // if we need filters
70  {
71  walls = new HiMidLow*[numMics_];
72  air = new LowPass*[numMics_];
73 
74  xfadeWalls = new HiMidLow*[numMics_];
75  xfadeAir = new LowPass[numMics_];
76 
77  for (int i = 0; i < numMics_; i++)
78  {
79  walls[i] = new HiMidLow[filtersPerMic_];
80  xfadeWalls[i] = new HiMidLow[3];
81 
82  air[i] = new LowPass[reflOrder_];
83  }
84  }
85 }
86 
88 {
89  if (reflOrder_ > 0)
90  {
91  for (int n = 0; n < numMics_; n++)
92  {
93  delete [] xfadeWalls[n];
94  delete [] walls[n];
95  delete [] air[n];
96  }
97 
98  delete [] xfadeWalls;
99  delete [] walls;
100  delete [] air;
101  delete [] xfadeAir;
102  }
103 
104  //delete [] sources;
105  delete sources;
106  delete [] mirrors;
107 }
108 
109 void Room::printWalls()
110 {
111  for (int m = 0; m < numMics_; m++)
112  {
113  for (int n = 0; n < filtersPerMic_; n++)
114  {
115  post("Mic[%d], wall[%d]: ", m, n);
116  walls[m][n].print();
117  }
118  }
119 }
120 
122 {
123  post("Width: %f, Depth %f, Height %f", width_, depth_, height_);
124  printWalls();
125 }
126 
127 // source has changed
129 {
130  mirrorFlag_ = true;
131  mics.flag(true);
132 }
133 
134 void Room::width(double newWidth)
135 {
136  if (newWidth <= Properties::MAX_ROOM_DIM && sources[0].checkWidth(newWidth) && mics.checkWidth(newWidth))
137  {
138  width_ = newWidth;
139  mirrorFlag_ = true;
140  sources[0].flag(true);
141  mics.flag(true);
142  if (globReportFlag)
143  post("/RoomWidth= %f", width_);
144  }
145  else if (globWarningFlag)
146  post("bad value for Room Width: %f", newWidth);
147 }
148 
149 void Room::height(double newHeight)
150 {
151  if (newHeight <= Properties::MAX_ROOM_DIM && sources[0].checkHeight(newHeight) && mics.checkHeight(newHeight))
152  {
153  height_ = newHeight;
154  mirrorFlag_ = true;
155  sources[0].flag(true);
156  mics.flag(true);
157  if (globReportFlag)
158  post("/RoomHeight = %f", width_);
159  }
160  else if (globWarningFlag)
161  post("bad value for Room height: %f", newHeight);
162 }
163 
164 void Room::depth(double newDepth)
165 {
166  if (newDepth <= Properties::MAX_ROOM_DIM && sources[0].checkDepth(newDepth) && mics.checkDepth(newDepth))
167  {
168  depth_ = newDepth;
169  mirrorFlag_ = true;
170  sources[0].flag(true);
171  mics.flag(true);
172  if (globReportFlag)
173  post("/RoomDepth = %f", depth_);
174  }
175  else if (globWarningFlag)
176  post("bad value for Room depth: %f", newDepth);
177 }
178 
179 double Room::width() const
180 {
181  return width_;
182 }
183 
184 double Room::depth() const
185 {
186  return depth_;
187 }
188 
189 double Room::height() const
190 {
191  return height_;
192 }
193 
194 double Room::halfWidth() const
195 {
196  return width_ * 0.5;
197 }
198 
199 double Room::halfDepth() const
200 {
201  return depth_ * 0.5;
202 }
203 
204 double Room::halfHeight() const
205 {
206  return height_ * 0.5;
207 }
208 
209 bool Room::mirrorFlag() const
210 {
211  return mirrorFlag_;
212 }
213 
215 {
216  // Estimation of mirror images
217  // direct sound source
218  mirrors[0].xPos(sources[0].xPos());
219  mirrors[0].yPos(sources[0].yPos());
220  mirrors[0].zPos(sources[0].zPos());
221 
222  // first order reflections
223  if (reflOrder_ > 0)
224  {
225  // left wall
226  mirrors[Properties::LEFT].xPos(-width_ - sources[0].xPos()); // case 6 -> .xPos(mirrors[Properties::LEFT].xPos());//
227  mirrors[Properties::LEFT].yPos(sources[0].yPos());
228  mirrors[Properties::LEFT].zPos(sources[0].zPos());
229 
230  //right wall
231  mirrors[Properties::RIGHT].xPos(width_ - sources[0].xPos()); // case 5 -> .xPos(mirrors[Properties::RIGHT].xPos());//
232  mirrors[Properties::RIGHT].yPos(sources[0].yPos());
233  mirrors[Properties::RIGHT].zPos(sources[0].zPos());
234 
235  // front wall
236  mirrors[Properties::FRONT].xPos(sources[0].xPos());
237  mirrors[Properties::FRONT].yPos(depth_ - sources[0].yPos()); //case 4 -> .yPos(mirrors[Properties::FRONT].yPos());//
238  mirrors[Properties::FRONT].zPos(sources[0].zPos());
239 
240  // rear wall
241  mirrors[Properties::REAR].xPos(sources[0].xPos());
242  mirrors[Properties::REAR].yPos(-depth_ - sources[0].yPos());//case 3 -> y.Pos(mirrors[REAR].yPos());//
243  mirrors[Properties::REAR].zPos(sources[0].zPos());
244 
245  // floor
246  mirrors[Properties::FLOOR].xPos(sources[0].xPos());
247  mirrors[Properties::FLOOR].yPos(sources[0].yPos());
248  mirrors[Properties::FLOOR].zPos(height_ - sources[0].zPos()); //case 2 -> z.Pos(mirrors[FLOOR].zPos());//
249 
250  // ceiling
251  mirrors[Properties::CEILING].xPos(sources[0].xPos());
252  mirrors[Properties::CEILING].yPos(sources[0].yPos());
253  mirrors[Properties::CEILING].zPos(-height_ - sources[0].zPos()); //case 1 -> z.Pos(mirrors[Properties::CEILING].zPos());//
254 
255  }
256  if (reflOrder_ > 1)
257  {
258  // second order reflections
259  //left wall/front wall
260  mirrors[Properties::LEFT_FRONT].xPos(mirrors[Properties::LEFT].xPos());//.xPos(-width_ - sources[0].xPos()); // case 6
261  mirrors[Properties::LEFT_FRONT].yPos(mirrors[Properties::FRONT].yPos());//.yPos(depth_ - sources[0].yPos());//case 4
262  mirrors[Properties::LEFT_FRONT].zPos(sources[0].zPos());
263 
264  // right wall/ front wall
265  mirrors[Properties::RIGHT_FRONT].xPos(mirrors[Properties::RIGHT].xPos());//.xPos(width_ - sources[0].xPos()); // case 5
266  mirrors[Properties::RIGHT_FRONT].yPos(mirrors[Properties::FRONT].yPos());//.yPos(depth_ - sources[0].yPos());//case 4
267  mirrors[Properties::RIGHT_FRONT].zPos(sources[0].zPos());
268 
269  // left wall/rear wall
270  mirrors[Properties::LEFT_REAR].xPos(mirrors[Properties::LEFT].xPos());//.xPos(-width_ - sources[0].xPos()); // case 6
271  mirrors[Properties::LEFT_REAR].yPos(mirrors[Properties::REAR].yPos());//.yPos(-depth_ - sources[0].yPos()); //case 3
272  mirrors[Properties::LEFT_REAR].zPos(sources[0].zPos());
273 
274  // right wall/rear wall
275  mirrors[Properties::RIGHT_REAR].xPos(mirrors[Properties::RIGHT].xPos());//.xPos(width_ - sources[0].xPos()); // case 5
276  mirrors[Properties::RIGHT_REAR].yPos(mirrors[Properties::REAR].yPos());//.yPos(-depth_ - sources[0].yPos()); //case 3
277  mirrors[Properties::RIGHT_REAR].zPos(sources[0].zPos());
278 
279  // left wall/floor
280  mirrors[Properties::LEFT_FLOOR].xPos(mirrors[Properties::LEFT].xPos());//.xPos(-width_ - sources[0].xPos()); // case 6
281  mirrors[Properties::LEFT_FLOOR].yPos(sources[0].yPos());
282  mirrors[Properties::LEFT_FLOOR].zPos(mirrors[Properties::FLOOR].zPos());//.zPos(height_ - sources[0].zPos()); //case 2
283 
284  // right wall/floor
285  mirrors[Properties::RIGHT_FLOOR].xPos(mirrors[Properties::RIGHT].xPos());//.xPos(width_ - sources[0].xPos()); // case 5
286  mirrors[Properties::RIGHT_FLOOR].yPos(sources[0].yPos());
287  mirrors[Properties::RIGHT_FLOOR].zPos(mirrors[Properties::FLOOR].zPos());//.zPos(height_ - sources[0].zPos()); //case 2
288 
289  // left wall/ceiling
290  mirrors[Properties::LEFT_CEILING].xPos(mirrors[Properties::LEFT].xPos());//.xPos(-width_ - sources[0].xPos()); // case 6
291  mirrors[Properties::LEFT_CEILING].yPos(sources[0].yPos());
292  mirrors[Properties::LEFT_CEILING].zPos(mirrors[Properties::CEILING].zPos());//.zPos(-height_ - sources[0].zPos()); //case 1
293 
294  // right wall/ceiling
295  mirrors[Properties::RIGHT_CEILING].xPos(mirrors[Properties::RIGHT].xPos());//.xPos(width_ - sources[0].xPos()); // case 5
296  mirrors[Properties::RIGHT_CEILING].yPos(sources[0].yPos());
297  mirrors[Properties::RIGHT_CEILING].zPos(mirrors[Properties::CEILING].zPos());//.zPos(-height_ - sources[0].zPos()); //case 1
298 
299  // front wall/floor
300  mirrors[Properties::FRONT_FLOOR].xPos(sources[0].xPos());
301  mirrors[Properties::FRONT_FLOOR].yPos(mirrors[Properties::FRONT].yPos());//.yPos(depth_ - sources[0].yPos()); //case 4
302  mirrors[Properties::FRONT_FLOOR].zPos(mirrors[Properties::FLOOR].zPos());//.zPos(height_ - sources[0].zPos()); //case 2
303 
304  // rear wall/floor
305  mirrors[Properties::REAR_FLOOR].xPos(sources[0].xPos());
306  mirrors[Properties::REAR_FLOOR].yPos(mirrors[Properties::REAR].yPos());//.yPos(-depth_ - sources[0].yPos()); //case 3
307  mirrors[Properties::REAR_FLOOR].zPos(mirrors[Properties::FLOOR].zPos());//.zPos(height_ - sources[0].zPos()); //case 2
308 
309  // front wall/ceiling
310  mirrors[Properties::FRONT_CEILING].xPos(sources[0].xPos());
311  mirrors[Properties::FRONT_CEILING].yPos(mirrors[Properties::FRONT].yPos());//.yPos(depth_ - sources[0].yPos()); //case 4
312  mirrors[Properties::FRONT_CEILING].zPos(mirrors[Properties::CEILING].zPos());//.zPos(-height_ - sources[0].zPos()); //case 1
313 
314  // rear wall/ceiling
315  mirrors[Properties::REAR_CEILING].xPos(sources[0].xPos());
316  mirrors[Properties::REAR_CEILING].yPos(mirrors[Properties::REAR].yPos());//.yPos(-depth_ - sources[0].yPos()); //case 3
317  mirrors[Properties::REAR_CEILING].zPos(mirrors[Properties::CEILING].zPos());//.zPos(-height_ - sources[0].zPos()); // case 1
318  }
319  mirrorFlag_ = false;
320  mics.flag(true);
321 }
322 
323 short Room::reflOrder() const
324 {
325  return reflOrder_;
326 }
327 
328 // vim:sw=4:et:cindent:
MicArray mics
Collection of mics.
Definition: Room.h:48
virtual void print() const
Prints information about this filter.
Definition: HiMidLow.cpp:198
Source * sources
Sound source.
Definition: Room.h:36
short reflOrder() const
Get reflection order (either 0, 1 or 2).
Definition: Room.cpp:323
void sourceChanged()
Allows source to notify mirror that it has changed.
Definition: Room.cpp:128
void print()
Print information about this room and its contents.
Definition: Room.cpp:121
LowPass * xfadeAir
Filters which simulate air absorption for XFADE_LITE mode.
Definition: Room.h:46
double depth() const
Get depth.
Definition: Room.cpp:184
HiMidLow filter class.
Definition: HiMidLow.h:22
double xPos() const
Get x position.
Definition: Moveable.cpp:26
bool flag() const
Returns true if the mic array has changed, false otherwise.
Definition: MicArray.cpp:219
double halfWidth() const
Get half width.
Definition: Room.cpp:194
bool checkDepth(double newDepth)
Checks that new room depth will not exclude any mics.
Definition: MicArray.cpp:234
bool checkHeight(double newHeight)
Checks that new room height will not exclude any mics.
Definition: MicArray.cpp:244
double width() const
Get width.
Definition: Room.cpp:179
~Room()
Class destructor.
Definition: Room.cpp:87
Low pass filter class.
Definition: LowPass.h:22
bool flag() const
True if object has moved.
Definition: Moveable.cpp:65
LowPass ** air
Filters which simulate air absorption.
Definition: Room.h:44
double zPos() const
Get z position.
Definition: Moveable.cpp:52
Room(double newWidth, double newDepth, double newHeight, short numChannels, short numSources, short reflOrder)
Class constructor.
Definition: Room.cpp:29
double height() const
Get height.
Definition: Room.cpp:189
double halfDepth() const
Get half depth.
Definition: Room.cpp:199
short order() const
Get order.
Definition: Mirror.cpp:28
bool mirrorFlag() const
Returns true if mirrors have changed.
Definition: Room.cpp:209
Sound mirror class.
Definition: Mirror.h:19
Mirror * mirrors
Sound mirrors.
Definition: Room.h:38
Sound source class.
Definition: Source.h:25
bool checkWidth(double newWidth)
Checks that new room width will not exclude any mics.
Definition: MicArray.cpp:224
MicArray class.
Definition: MicArray.h:21
double yPos() const
Get y position.
Definition: Moveable.cpp:39
double halfHeight() const
Get half height.
Definition: Room.cpp:204
HiMidLow ** walls
Filters which simulate room damping.
Definition: Room.h:40
HiMidLow ** xfadeWalls
Filters which simulate room damping for XFADE_LITE mode.
Definition: Room.h:42
void renderMirrors()
Update mirrors.
Definition: Room.cpp:214