Jamoma API  0.6.0.a19
ViMic_Engine.cpp
1 // ViMic_Engine.c
2 // Handles sensitivity calculations
3 
4 #include <cmath>
5 #include "ViMic_Engine.h"
6 #include "CrossFadeQueue.h"
7 #include "Properties.h"
8 #include "Mirror.h"
9 #include "Mic.h"
10 #include "Source.h"
11 #include "TTDSP.h"
12 
13 extern bool globWarningFlag;
14 extern bool globReportFlag;
15 
16 void vimic_mirrors(double *sensi,
17  double *delay,
18  Mic *mic,
19  Mirror *mirror,
20  Source *source,
21  double invSpeedofsound,
22  int NumOfRefl,
23  Properties::AudioProcess mode,
24  double *oldDelay,
25  double *reflGains,
26  CrossFadeQueue *fades,
27  double Polarity,
28  int distModel)
29 {
30  int n;
31  for (n = 0; n < NumOfRefl; n++)
32  vimic_sensitivity(sensi + n, delay + n, mic, mirror + n, source, invSpeedofsound, mode, oldDelay, reflGains, fades, n, Polarity, distModel);
33 }
34 
35 void vimic_sensitivity(double *sensi, double *del, Mic *mic, Mirror *mirror, Source *source, double One_over_Speedofsound, Properties::AudioProcess mode, double *oldDelay, double *reflGains, CrossFadeQueue *fades, int reflNum, double Polarity, int distModel)
36 {
37  int order = mirror->order();
38  if (mic->gain() != 0.0 || reflGains[order] != 0.0) // should be || for correct updating
39  {
40  double orient[3];
41  double distance;//, invDistance;
42  double newDel = 0.0;
43  double newSensi = 0.0;
44  double cosAng;
45  double tempcos;
46  int radiationAngle;
47 
48  orient[0] = mirror->xPos() - mic->xPos();
49  orient[1] = mirror->yPos() - mic->yPos();
50  orient[2] = mirror->zPos() - mic->zPos();
51  distance = sqrt((orient[0] * orient[0]) + (orient[1] * orient[1]) + (orient[2] * orient[2]));
52  TTLimitMin(distance, 0.1);
53 
54  tempcos = cos(mic->ele());
55  cosAng = (orient[0] * sin(mic->azi()) * tempcos + orient[1] * cos(mic->azi()) * tempcos + orient[2] * sin(mic->ele())) / distance;
56  TTLimit(cosAng, -1.0, 1.0); // MAKING SURE IT'S NOT A NaN
57 
58  newSensi = pow((mic->dirGainA() + (mic->dirGainB() * cosAng)), mic->dirPow());
59 
60  if (distModel == 1) {
61  newSensi *= pow(distance, mic->distPow()); // inverse proportional decrease
62  } else { //if (distModel == 2)
63  //exponential decrease
64  newSensi *= pow(10.0,(distance* mic->dbUnit()));
65  }
66 
67  // Source Directivity ... frequency independent...so far
68 
69  if (source->directivityFlag()) {
70  switch(reflNum)
71  {
72  case 0: //DIRECT SOUND
73  radiationAngle = atan2(orient[0], orient[1]) * Properties::RAD2DEG + 180.5 - source->aziAngle();
74  radiationAngle = radiationAngle - 360 * (int) floor(radiationAngle * Properties::ONE_OVER_360); // modulo operation, to keep the angle between 0..359 degree
75  newSensi *= (double) source->directivityAt(radiationAngle);
76  if (globReportFlag)
77  post ("Direct Sound: radiationAngle: %d", radiationAngle);
78  break;
79  case 1: //left wall
80  case 2: //right wall
81  radiationAngle = 180.5 - (atan2(orient[0], orient[1]) * Properties::RAD2DEG) - source->aziAngle();
82  radiationAngle = radiationAngle - 360 * (int) floor(radiationAngle * Properties::ONE_OVER_360); // modulo operation, to keep the angle between 0..359 degree
83  newSensi *= (double) source->directivityAt(radiationAngle);
84  if (globReportFlag)
85  post ("radiationAngle for Refl. %d : %d",reflNum, radiationAngle);
86  break;
87 
88  case 3://front wall
89  case 4://back wall
90  radiationAngle = 360.5 - (atan2(orient[0], orient[1]) * Properties::RAD2DEG) - source->aziAngle();
91  radiationAngle = radiationAngle - 360 * (int) floor(radiationAngle * Properties::ONE_OVER_360); // modulo operation, to keep the angle between 0..359 degree
92  newSensi *= (double) source->directivityAt(radiationAngle);
93  if (globReportFlag)
94  post ("radiationAngle for Refl. %d : %d",reflNum, radiationAngle);
95  break;
96 
97  default: //for simplification we treat all other walls in the same way
98  newSensi *= (double) source->directivityAt(360); //the 360th entry of the directivity-table contains the mean directivity value
99  //if (globReportFlag)
100  // post ("mean directivity gain: %f", sourceDirectivity);
101  break;
102  }
103  }
104 
105  newSensi *= mic->gain();
106  newSensi *= reflGains[order];
107 
108 #ifndef __INTEL_COMPILER // with icc, we use the flushtozero flag which takes care of that
109  TTZeroDenormal(newSensi);
110 #endif
111  TTLimit(newSensi, Polarity, 1.0);
112 
113  /*if (newSensi > 1.0)
114  {
115  if (globWarningFlag)
116  post("Sensitivity %f capped at 1.0", newSensi);
117  newSensi = 1.0; // clip to maximum gain
118  }
119  else if (newSensi < Polarity)//-1.0) //TODO: option restrict polarity, if (newSensi < 0).... newSensi = 0;
120  {
121  if (globWarningFlag)
122  post("Sensitivity %f capped at %f", newSensi, Polarity);
123  newSensi = Polarity;//-1.0; // clip to minimum gain
124  }
125  else if (IEM_NAN(newSensi)) // if it's NAN
126  {
127  newSensi = 0.0;
128  if (globWarningFlag)
129  error("Sensitivity caused a NaN!");
130  }*/
131 #if 0
132  else if (newSensi != 0.0 && IEM_DENORMAL(newSensi)) // if it's denormal
133  {
134  if (globWarningFlag)
135  error("Sensitivity caused a denormal, equal to %f", newSensi);
136  // newSensi = 0.0;
137  }
138 #endif
139 
140  // only update if we're not in xfade more, or if we are, the fade is either inactive or at the start
141  // we don't want a moving target!
142  if (!(mode == Properties::X_FADE_LITE || mode == Properties::X_FADE_XL) || !fades->isActive() || fades->atStart())
143  *sensi = newSensi;
144 
145  newDel = distance * One_over_Speedofsound;
146  TTLimit(newDel, 0.0, double(Properties::DELAYSIZE)); // check for abnormal values
147 
148  /*if (newDel >= Properties::DELAYSIZE) // cap max delay time
149  {
150  newDel = Properties::DELAYSIZE;
151  if (globWarningFlag)
152  post("Delay time capped at %f", newDel);
153  }*/
154 
155  // only update delay time if it's >= 0, and we're not in crossfade more, or if we are, we are not in the middle of a crossfade
156 
157  if (newDel != *del)
158  {
159  if (newDel >= 0.0 && (!(mode == Properties::X_FADE_LITE || mode == Properties::X_FADE_XL) || (!fades->isActive() || fades->atStart())))
160  *del = newDel;
161  else if (newDel < 0.0)
162  post("new Delay less than 0: %f", newDel);
163 
164  if (/*order == DIRECT &&*/ (abs(*del - *oldDelay) > fades->fadeThreshold()
165  && (mode == Properties::X_FADE_LITE || mode == Properties::X_FADE_XL)))
166  {
167  if (fades->startFade() && globReportFlag)
168  post("new del: %f, old del: %f", *del, *oldDelay);
169  }
170  }
171  }
172  else
173  *sensi = 0.0;
174 }
175 
176 // returns inverse of sqrt of sum of sensitivities squared
177 double vimic_invSqrtSumSensi(double *sensi, long size)
178 {
179  double sum = 0.0;
180 
181  for (int i = 0; i < size; i++)
182  sum += sensi[i] * sensi[i];
183 
184  return pow(sum, -0.5); //equals to 1.0 / sqrt(sum);
185 }
186 
187 void vimic_floorSensi(double *sensi, double minSensi)
188 {
189  if (abs(*sensi) < minSensi)
190  *sensi = 0.0;
191 }
192 
193 // normalizes sensitivity based on a given maximum, which must be given as the inverse
194 void vimic_normalizeSensi(double *sensi, double invMax)
195 {
196  *sensi = (*sensi) * invMax;
197 }
198 
199 void vimic_minimizeDelay(double *delay, double minValue)
200 {
201  *delay = (*delay) - minValue;
202 }
203 
204 double vimic_findMinDelayValue(double *delay, long size)
205 {
206  double minDelayValue = delay[0];
207 
208  for (int i = 1; i < size; i++) {
209  if (delay[i] < minDelayValue)
210  minDelayValue = delay[i];
211  }
212  return minDelayValue;
213 }
void dbUnit(double newDbUnit)
Set dbUnit for exponential distance model.
Definition: Mic.cpp:193
bool directivityFlag() const
True if the source's directivity is to be taken into account, false otherwise.
Definition: Source.cpp:192
void dirPow(double newDirPow)
Set directivity power.
Definition: Mic.cpp:131
long fadeThreshold() const
Get fade threshold in samples.
void distPow(double newDistPow)
Set distance power.
Definition: Mic.cpp:163
void aziAngle(long angle)
Change azimuth angle, and those of all the mirrors.
Definition: Source.cpp:68
bool atStart() const
True if at beginning of crossfade.
bool isActive() const
True if a crossfade is underway, false othewise.
Jamoma DSP Library.
double xPos() const
Get x position.
Definition: Moveable.cpp:26
void dirGainA(double newDirGainA)
Set directivity gain a.
Definition: Mic.cpp:96
bool startFade()
Triggers a crossfade, returns true if fade has started.
void azi(double angle)
Set azimuth angle.
Definition: Mic.cpp:68
CrossFadeQueue class.
void ele(double angle)
Set elevation angle.
Definition: Mic.cpp:82
double dirGainB() const
Get directivity gain b.
Definition: Mic.cpp:126
double directivityAt(long angle) const
Retrieve directivity gain for a given angle.
Definition: Source.cpp:53
Microphone class.
Definition: Mic.h:22
double zPos() const
Get z position.
Definition: Moveable.cpp:52
short order() const
Get order.
Definition: Mirror.cpp:28
void gain(double newGain)
Set gain.
Definition: Mic.cpp:224
Sound mirror class.
Definition: Mirror.h:19
Sound source class.
Definition: Source.h:25
double yPos() const
Get y position.
Definition: Moveable.cpp:39