Jamoma API  0.6.0.a19
j.vimic~.cpp
1 #include "j.vimic~.h"
2 #include "ViMic_Engine.h"
3 #include "Properties.h"
4 #include "Mic.h"
5 #include "MicArray.h"
6 #include "Mirror.h"
7 #include "Room.h"
8 #include "Filter.h"
9 #include "HiMidLow.h"
10 #include "LowPass.h"
11 #include "Source.h"
12 #include "ext_common.h"
13 //#include "ext_critical.h"
14 #include "TTClassWrapperMax.h"
15 #include "TTDSP.h"
16 
17 bool globWarningFlag;
18 bool globReportFlag;
19 
20 /// Setup max class and bind messages to corresponding handlers.
21 int C74_EXPORT main(void)
22 {
23  t_class *c;
24 
25  TTDSPInit();
26  common_symbols_init();
27 
28  c = class_new("j.vimic~", (method)vimic_new, (method)vimic_free, sizeof(t_vimic), (method)0L, A_GIMME, 0);
29  //setup((t_messlist**)&vimic_class, (method)vimic_new, (method)vimic_free, sizeof(t_vimic), 0L, A_GIMME, 0);
30 
31  class_addmethod(c,(method)vimic_dsp, "dsp", A_CANT, 0);
32  class_addmethod(c,(method)vimic_dsp64, "dsp64", A_CANT, 0);
33  class_addmethod(c,(method)vimic_bang, "bang", 0);
34  /*----------------------------------------------*/
35  /* Bind to corresponding methods */
36  /*----------------------------------------------*/
37  class_addmethod(c,(method)vimic_sourcePosAbs, "sourcePosAbs", A_GIMME, 0);
38  class_addmethod(c,(method)vimic_sourcePos, "sourcePos", A_GIMME, 0);
39  class_addmethod(c,(method)vimic_reflGain, "reflGain", A_GIMME, 0);
40  class_addmethod(c,(method)vimic_micPos, "micPos", A_GIMME, 0);
41  class_addmethod(c,(method)vimic_micAngle, "micAngle", A_GIMME, 0);
42  class_addmethod(c,(method)vimic_micDirectivity, "directivity", A_GIMME, 0);
43  class_addmethod(c,(method)vimic_micGain, "micGain", A_GIMME, 0);
44  class_addmethod(c,(method)vimic_roomSize, "roomSize", A_GIMME, 0);
45  class_addmethod(c,(method)vimic_disPow, "disPow", A_GIMME, 0);
46  class_addmethod(c,(method)vimic_dirPow, "dirPow", A_GIMME, 0);
47  class_addmethod(c,(method)vimic_dbUnit, "dbUnit", A_GIMME, 0);
48  class_addmethod(c,(method)vimic_temperature, "temperature", A_FLOAT, 0);
49  class_addmethod(c,(method)vimic_minSensi, "minSensi", A_FLOAT, 0);
50  class_addmethod(c,(method)vimic_directBang, "directBang", A_LONG, 0);
51  class_addmethod(c,(method)vimic_micPolarity, "micPolarity", A_LONG, 0);
52  class_addmethod(c,(method)vimic_distModel, "distModel", A_LONG, 0);
53  class_addmethod(c,(method)vimic_renderType, "renderType", A_LONG, 0);
54  class_addmethod(c,(method)vimic_report, "report", A_LONG, 0);
55  class_addmethod(c,(method)vimic_sourceYaw, "sourceYaw", A_LONG, 0);
56  class_addmethod(c,(method)vimic_renderintervall, "renderintervall", A_LONG, 0);
57  class_addmethod(c,(method)vimic_sourceDirectivityFlag, "sourceDirectivityFlag", A_LONG, 0);
58  class_addmethod(c,(method)vimic_normalizeSensiFlag, "normalizeSensiFlag", A_LONG, 0);
59  class_addmethod(c,(method)vimic_minimumDelayFlag, "minimumDelayFlag", A_LONG, 0);
60  class_addmethod(c,(method)vimic_minSensiFlag, "minSensiFlag", A_LONG, 0);
61  class_addmethod(c,(method)vimic_xFadeLength, "xFadeLength", A_LONG, 0);
62  class_addmethod(c,(method)vimic_xFadeFunction, "xFadeFunction", A_LONG, 0);
63  class_addmethod(c,(method)vimic_xFadeThreshold, "xFadeThreshold", A_LONG, 0);
64  class_addmethod(c,(method)vimic_reportAll, "reportAll", 0);
65  class_addmethod(c,(method)vimic_warnings, "warnings", A_LONG, 0);
66  class_addmethod(c,(method)vimic_airfilter, "airfilter", A_LONG, 0);
67  class_addmethod(c,(method)vimic_getDirTable, "getDirTable", A_DEFSYM, 0);
68  class_addmethod(c,(method)vimic_highCf, "highCf", A_LONG, A_LONG, 0);
69  class_addmethod(c,(method)vimic_lowCf, "lowCf", A_LONG, A_LONG, 0);
70  class_addmethod(c,(method)vimic_lowAbsorption, "lowAbsorption", A_GIMME, 0);
71  class_addmethod(c,(method)vimic_midAbsorption, "midAbsorption", A_GIMME, 0);
72  class_addmethod(c,(method)vimic_highAbsorption, "highAbsorption", A_GIMME, 0);
73  class_addmethod(c,(method)vimic_wallFilter, "wallFilter", A_GIMME, 0);
74  class_addmethod(c,(method)vimic_assist, "assist",A_CANT,0);
75 
76 #ifdef __INTEL_COMPILER
77  post("ViMiC for Max/MSP, © 2005-2012 Nils Peters, Tristan Matthews, Jonas Braasch. Version built with icc on " __DATE__ " at " __TIME__);
78 #else
79  post("ViMiC for Max/MSP, © 2005-2012 Nils Peters, Tristan Matthews, Jonas Braasch. Version built on " __DATE__ " at " __TIME__);
80 #endif
81 
82  class_dspinit(c);
83  class_register(CLASS_BOX, c);
84  vimic_class = c;
85  return 0;
86 }
87 
88 /// Object creation method
89 void *vimic_new(t_symbol *s, int argc, t_atom *argv)
90 {
91  long n;
92  t_vimic *x = (t_vimic*)object_alloc(vimic_class);
93  if (x) {
94  x->numOfSources = 1;
95  x->numOfChannels = 8;
96  x->reflOrder = 2;
97  x->maxReflOrder = 2; //TODO: we don't really need this, don'twe
98  globWarningFlag = false;
99  globReportFlag = false;
100  x->normalizeSensiFlag = false;
101  x->minSensiFlag = false;
102  x->minimumDelayFlag = false;
103  x->minSensi = 0.0;
104  x->distModel = 1;
105 
106  if (argc) {
107  if (argv[0].a_w.w_long > 0 && argv[0].a_w.w_long <= Properties::MAXNUMCHANNELS)
108  x->numOfChannels = (int) argv[0].a_w.w_long;
109  else if (globWarningFlag)
110  post("requested number of channels could not be set. Set to default of 8 instead");
111  /*if (argv[1].a_w.w_long >= 0 && argv[1].a_w.w_long <= Properties::REFLECTIONORDER)
112  x->maxReflOrder = (int) argv[1].a_w.w_long;
113  else if (globWarningFlag)
114  post("requested reflection order could not be set. Set to default of 1 instead");*/
115  }
116 
117  //x->reflOrder = x->maxReflOrder;
118 
119  dsp_setup((t_pxobject*)x, 1); // one signal inlet
120 
121  /*
122  According to the image Model the number of Reflections can be determined based on the Reflection Order
123  that is how many times a ray is allowed to hit a wall.
124  */
125 
126  /*if (x->reflOrder < 0 || x->reflOrder > 3)
127  {
128  post("Invalid reflection order, defaulting to 2.");
129  x->reflOrder = 2;
130  }*/
131  x->numRefl = Properties::REFLECTIONS_PER_REFLECTION_ORDER[x->reflOrder];
132 
133  x->maxDynRefl = x->numRefl;
134  x->reflGains[0] = 0.0;
135  x->reflGains[1] = 0.0;
136  x->reflGains[2] = 0.0;
137  x->reflGainFlag = true;
138 
139  x->bufSz = x->numRefl * x->numOfChannels;
140 
141  x->room = new Room(20, 30, 8, x->numOfChannels, x->numOfSources, x->reflOrder); // width, depth, height, channels, sources, reflection order
142 
143  x->AudioProcType = Properties::VIMIC_LITE; // Set to ViMiC
144  x->c_phase = 0;
145  x->directBang = 0;
146  x->x_sr = Properties::SAMPLERATE;
147  x->micPolarity = -1.0;
148  /////
149  x->renderInterval = 50;
150  x->blocksize = 64;
151  x->grainsize = (double) 1.0 / (x->renderInterval * x->blocksize);
152 
153  ///////////////////x-fade parameter
154  x->fades = new CrossFadeQueue(10, Properties::FADE_TABLE_SIZE, Properties::COS, x->x_sr);
155 
156  ////////////////// air properties
157  x->temperature = 21; //degree Celsius
158  x->speedOfSound = (331.3 * sqrt(1.0 + x->temperature / 273.15)) / x->x_sr; //x->temperature/x->x_sr; //331.3*sqrt(1+temp/273.15)
159  x->invSpeedOfSound = 1.0 / x->speedOfSound;
160 
161  if ((x->c_vec = (double *) malloc(Properties::DELAYBYTES * sizeof(double))) == NULL)
162  exit(EXIT_FAILURE);
163 
164  for (n = 0; n < Properties::DELAYBYTES; n++)
165  x->c_vec[n] = 0.0;
166 
167  if ((x->delay = (double *) getbytes((short) x->bufSz * sizeof(double))) == NULL)
168  exit(EXIT_FAILURE);
169  if ((x->currentDelay = (double *) getbytes((short) x->bufSz * sizeof(double))) == NULL)
170  exit(EXIT_FAILURE);
171  if ((x->delGrain= (double *) getbytes((short) x->bufSz * sizeof(double))) == NULL)
172  exit(EXIT_FAILURE);
173  if ((x->sensiGrain= (double *) getbytes((short) x->bufSz * sizeof(double))) == NULL)
174  exit(EXIT_FAILURE);
175  if ((x->sensitivity= (double *) getbytes((short) x->bufSz * sizeof(double))) == NULL)
176  exit(EXIT_FAILURE);
177  if ((x->currentSensitivity= (double *) getbytes((short) x->bufSz * sizeof(double))) == NULL)
178  exit(EXIT_FAILURE);
179 
180  for (n = 0; n < x->bufSz; n++) {
181  x->currentDelay[n] = 0.0;
182  x->delay[n] = 0.0;
183  x->sensitivity[n] = 0.0;
184  x->currentSensitivity[n] = 0.0;
185  x->delGrain[n] = 0.0;
186  x->sensiGrain[n] = 0.0;
187  }
188  x->grainCounter = 0;
189 
190  for (n = 0; n < x->numOfChannels; n++)
191  outlet_new((t_pxobject *)x, "signal");
192 
193  x->room->renderMirrors();
194  x->room->mics.renderMics();
195  }
196  return x;
197 }
198 
199 /// Memory deallocation
200 void vimic_free(t_vimic *x)
201 {
202  dsp_free((t_pxobject*)x);
203  free(x->c_vec);
204  freebytes(x->delay, (short) x->bufSz * sizeof(double));
205  freebytes(x->currentDelay, (short) x->bufSz * sizeof(double));
206  freebytes(x->delGrain, (short) x->bufSz * sizeof(double));
207  freebytes(x->sensiGrain, (short) x->bufSz * sizeof(double));
208  freebytes(x->sensitivity, (short) x->bufSz * sizeof(double));
209  freebytes(x->currentSensitivity, (short) x->bufSz * sizeof(double));
210 
211  // Freeing of objects or arrays of objects instantiated with cpp operator "new" must be done with "delete"
212  delete x->fades;
213  delete x->room;
214 }
215 
216 void vimic_sourcePosAbs(t_vimic *x, t_symbol *s, short argc, t_atom *argv)
217 {
218  if (argc == 3)
219  {
220  if (argv[0].a_type == A_FLOAT) // First variable is x coordinate
221  {
222  x->room->sources[0].xPosAbs(argv[0].a_w.w_float);
223 
224  if (argv[1].a_type == A_FLOAT) // Second variable is y coordinate
225  {
226  x->room->sources[0].yPosAbs(argv[1].a_w.w_float);
227 
228  if (argv[2].a_type == A_FLOAT) // Third variable is z coordinate
229  x->room->sources[0].zPosAbs(argv[2].a_w.w_float);
230  }
231  }
232  if (x->directBang == 1) vimic_bang(x);
233  }
234  else if (globWarningFlag) error("Numbers of args. is wrong");
235 
236 }
237 
238 
239 void vimic_sourcePos(t_vimic *x, t_symbol *s, short argc, t_atom *argv)
240 {
241  if (argc == 3)
242  {
243  if (argv[0].a_type == A_FLOAT) // First variable is x coordinate
244  {
245  x->room->sources[0].xPosRel(argv[0].a_w.w_float);
246 
247  if (argv[1].a_type == A_FLOAT) // Second variable is y coordinate
248  {
249  x->room->sources[0].yPosRel(argv[1].a_w.w_float);
250 
251  if (argv[2].a_type == A_FLOAT) // Third variable is z coordinate
252  x->room->sources[0].zPosRel(argv[2].a_w.w_float);
253  }
254  }
255  if (x->directBang == 1) vimic_bang(x);
256  }
257  else if (globWarningFlag) error("Numbers of args. is wrong");
258 }
259 
260 
261 void vimic_micPos(t_vimic *x, t_symbol *s, short argc, t_atom *argv)
262 {
263  long b = 0;
264 
265  switch (argc)
266  {
267  case 3: // All mics
268  if (argv[0].a_type == A_FLOAT) // First variable is x coordinate
269  {
270  x->room->mics.xPos(argv[0].a_w.w_float);
271  if (argv[1].a_type == A_FLOAT) // Second variable is y coordinate
272  {
273  x->room->mics.yPos(argv[1].a_w.w_float);
274 
275  if (argv[2].a_type == A_FLOAT) // Third variable is z coordinate
276  x->room->mics.zPos(argv[2].a_w.w_float);
277  }
278  }
279  break;
280  case 4: // one mic
281  if (argv[0].a_type == A_LONG) // index
282  b = argv[0].a_w.w_long; // get index
283 
284  if (x->room->mics.validChannel(b))
285  {
286  // get X-coordinate
287  x->room->mics[b - 1].xPos(argv[1].a_w.w_float);
288 
289  // get Y-coordinate
290  x->room->mics[b - 1].yPos(argv[2].a_w.w_float);
291 
292  // get Z-coordinate
293  x->room->mics[b - 1].zPos(argv[3].a_w.w_float);
294  }
295  else if (globWarningFlag) post("Invalid channel number %d", b);
296  break;
297  default:
298  if (globWarningFlag) error("Incorrect # of args.");
299  break;
300  }
301  if (x->directBang == 1) vimic_bang(x);
302 }// of "/MicPos"
303 
304 
305 
306 
307 void vimic_micAngle(t_vimic *x, t_symbol *s, short argc, t_atom *argv)
308 {
309  long b = 0;
310 
311  if (argc == 3)
312  {
313  if (argv[0].a_type == A_LONG) // index for microphone
314  {
315  b = argv[0].a_w.w_long;
316  if (argv[1].a_type == A_FLOAT) // azimuth angle
317  {
318  if (x->room->mics.validChannel(b))
319  {
320  x->room->mics[b - 1].azi(argv[1].a_w.w_float);
321 
322  if (argv[2].a_type == A_FLOAT) // elevation angle
323  x->room->mics[b - 1].ele(argv[2].a_w.w_float);
324  }
325  else if (globWarningFlag) post("Invalid channel number %d", b);
326  }
327  }
328  if (x->directBang == 1) vimic_bang(x);
329  }
330  else if (globWarningFlag) error("Incorrect # of args.");
331 }
332 
333 
334 void vimic_micDirectivity(t_vimic *x, t_symbol *s, short argc, t_atom *argv)
335 {
336  long b = 0;
337  switch (argc)
338  {
339  case 2: //two parameters
340  if (argv[0].a_type == A_LONG) //case 2: /directivity [index(int) value(float)]
341  {
342  b = argv[0].a_w.w_long;
343  if (argv[1].a_type == A_FLOAT) // one mic with index b=argv[0]
344  {
345  if (x->room->mics.validChannel(b))
346  x->room->mics[b - 1].dirGainA(argv[1].a_w.w_float);
347  else if (globWarningFlag) post("Invalid channel number %d", b);
348  }
349  }
350  break;
351  case 1: //one parameter
352  if (argv[0].a_type == A_FLOAT)// else // all microphones
353  x->room->mics.dirGain(argv[0].a_w.w_float);
354  break;
355  default:
356  if (globWarningFlag) error("Incorrect # of args.");
357  break;
358  }
359  if (x->directBang == 1) vimic_bang(x);
360 }
361 
362 void vimic_micGain(t_vimic *x, t_symbol *s, short argc, t_atom *argv)
363 {
364  long b = 0;
365 
366  switch (argc)
367  {
368  case 2:
369  if (argv[0].a_type == A_LONG)
370  {
371  b = argv[0].a_w.w_long;
372  if (argv[1].a_type == A_FLOAT) // one mic with index b=argv[0]
373  {
374  if (x->room->mics.validChannel(b))
375  x->room->mics[b - 1].gain(argv[1].a_w.w_float);
376  else if (globWarningFlag) error("Invalid channel number %d", b);
377  }
378  }
379  break;
380  case 1:
381  if (argv[0].a_type == A_FLOAT) // all microphones
382  x->room->mics.gain(argv[0].a_w.w_float);
383  break;
384  default:
385  if (globWarningFlag) error("Incorrect # of args.");
386  break;
387  }
388  if (x->directBang == 1) vimic_bang(x);
389 }
390 
391 
392 
393 void vimic_roomSize(t_vimic *x, t_symbol *s, short argc, t_atom *argv)
394 {
395  if (argc == 3)
396  {
397  if (argv[0].a_type == A_FLOAT) // First variable is x coordinate
398  {
399  x->room->width(argv[0].a_w.w_float);
400 
401  if (argv[1].a_type == A_FLOAT) // Second variable is y coordinate
402  {
403  x->room->depth(argv[1].a_w.w_float);
404 
405  if (argv[2].a_type == A_FLOAT) // Third variable is z coordinate
406  x->room->height(argv[2].a_w.w_float);
407  }
408  }
409  if (x->directBang == 1) vimic_bang(x);
410  }
411  else if (globWarningFlag)
412  error("Incorrect # of args.");
413 }
414 
415 
416 
417 void vimic_reflGain(t_vimic *x, t_symbol *s, short argc, t_atom *argv) //TODO change to long float
418 {
419  long b = 0;
420 
421  if (argc == 2)
422  {
423  if (argv[0].a_type == A_LONG)
424  {
425  b = argv[0].a_w.w_long;
426  if (b >= 0 && b < Properties::REFLECTIONORDER)
427  {
428  if (argv[1].a_type == A_FLOAT)
429  {
430  //if (argv[1].a_w.w_float <= 8.0 && argv[1].a_w.w_float >= 0.0)
431  //{
432  x->reflGains[b] = TTClip<float>(argv[1].a_w.w_float,0.0, 8.0);
433 
434  if (x->reflGains[2] > 0.0) {
435  x->reflOrder = 2;
436  x->numRefl = Properties::REFLECTIONS_PER_REFLECTION_ORDER[x->reflOrder];
437  x->maxReflOrder = x->reflOrder;
438  x->maxDynRefl = x->numRefl;
439  }
440  else if (x->reflGains[1] > 0.0) {
441  x->reflOrder = 1;
442  x->numRefl = Properties::REFLECTIONS_PER_REFLECTION_ORDER[x->reflOrder];
443  x->maxReflOrder = x->reflOrder;
444  x->maxDynRefl = x->numRefl;
445  }
446  else {
447  x->reflOrder = 0;
448  x->numRefl = Properties::REFLECTIONS_PER_REFLECTION_ORDER[x->reflOrder];
449  x->maxReflOrder = x->reflOrder;
450  x->maxDynRefl = x->numRefl;
451  }
452 
453  x->reflGainFlag = true;
454 
455  if (globReportFlag)
456  post("Reflection order %d gain: %f", b, x->reflGains[b]);
457 
458  }
459  }
460  else if (globWarningFlag) post("Invalid channel number %d", b);
461  }
462  if (x->directBang == 1) vimic_bang(x);
463  }
464  else if (globWarningFlag) error("Incorrect # of args.");
465 }
466 
467 
468 void vimic_dirPow(t_vimic *x, t_symbol *s, short argc, t_atom *argv)
469 {
470  long b = 0;
471 
472  switch (argc)
473  {
474  case 2:
475  if (argv[0].a_type == A_LONG)
476  {
477  b = argv[0].a_w.w_long;
478  if (argv[1].a_type == A_LONG) // one mic with index b=argv[0]
479  {
480  if (x->room->mics.validChannel(b))
481  x->room->mics[b - 1].dirPow(argv[1].a_w.w_long);
482  else if (globWarningFlag)
483  error("Invalid channel number %d", b);
484  }
485  }
486  break;
487  case 1:
488  if (argv[0].a_type == A_LONG) // all microphones
489  x->room->mics.dirPow(argv[0].a_w.w_long);
490  break;
491  default:
492  if (globWarningFlag)
493  error("Incorrect # of args.");
494  break;
495  }
496  if (x->directBang == 1) vimic_bang(x);
497 }
498 
499 void vimic_disPow(t_vimic *x, t_symbol *s, short argc, t_atom *argv)
500 {
501  long b = 0;
502  switch (argc)
503  {
504  case 2:
505  if (argv[0].a_type == A_LONG)
506  {
507  b = argv[0].a_w.w_long;
508  if (argv[1].a_type == A_FLOAT) // one mic with index b=argv[0]
509  {
510  if (x->room->mics.validChannel(b))
511  x->room->mics[b - 1].distPow(argv[1].a_w.w_float);
512  else if (globWarningFlag)
513  error("Invalid channel number %d", b);
514  }
515  }
516  break;
517  case 1:
518  if (argv[0].a_type == A_FLOAT) // all microphones
519  x->room->mics.distPow(argv[0].a_w.w_float);
520  break;
521  default:
522  if (globWarningFlag)
523  error("Incorrect # of args.");
524  break;
525  }
526  if (x->directBang == 1) vimic_bang(x);
527 }
528 
529 
530 void vimic_dbUnit(t_vimic *x, t_symbol *s, short argc, t_atom *argv)
531 {
532  long b = 0;
533 
534  switch (argc)
535  {
536  case 2:
537  if (argv[0].a_type == A_LONG)
538  {
539  b = argv[0].a_w.w_long;
540  if (argv[1].a_type == A_FLOAT) // one mic with index b=argv[0]
541  {
542  if (x->room->mics.validChannel(b))
543  x->room->mics[b - 1].dbUnit(argv[1].a_w.w_float);
544  else if (globWarningFlag) error("Invalid channel number %d", b);
545  }
546  }
547  break;
548  case 1:
549  if (argv[0].a_type == A_FLOAT) // all microphones
550  x->room->mics.dbUnit(argv[0].a_w.w_float);
551  break;
552  default:
553  if (globWarningFlag) error("Incorrect # of args.");
554  break;
555  }
556  if (x->directBang == 1) vimic_bang(x);
557 }
558 
559 
560 
561 void vimic_directBang(t_vimic *x, long n)
562 {
563  if (n == 1)
564  {
565  x->directBang = 1;
566  post("Automatic Rendering Update: On");
567  }
568  else
569  {
570  x->directBang = 0;
571  post("Automatic Rendering Update: Off");
572  }
573 }
574 
575 
576 
577 
578 void vimic_temperature(t_vimic *x, double n)
579 {
580  if ((n >= -20.0)||(n <= 40.0))
581  {
582  x->temperature = n;
583  x->speedOfSound = (331.3 * sqrt(1.0 + x->temperature / 273.15)) / x->x_sr;
584  x->invSpeedOfSound = 1.0 / x->speedOfSound;
585  if (globReportFlag) post("expected speed of sound is %f at %f degree celius", x->speedOfSound * x->x_sr, x->temperature);
586  if (x->directBang == 1) vimic_bang(x);
587  }
588  else if (globWarningFlag) post("Temperature must be between -20 and 40 degree");
589 
590 }
591 
592 void vimic_minSensi(t_vimic *x, double n)
593 {
594 
595  if (n >= 0.0 && n <= 1.0)
596  {
597  x->minSensi = n;
598  x->room->sources[0].flag(true);
599  if (x->directBang == 1) vimic_bang(x);
600  if (globReportFlag) post("Minimum sensitivity: %f", x->minSensi);
601  }
602  else if (globWarningFlag) error("Minimum sensitivity must be >= 0.0 and <= 1.0");
603 }
604 
605 
606 
607 
608 
609 
610 void vimic_distModel(t_vimic *x, long n)
611 {
612  x->distModel = TTClip<int>(n,1,2);
613  x->room->sources[0].flag(true);
614  if (x->directBang == 1) vimic_bang(x);
615  // modelID 1 for inverse proportional decrease
616  // modelID 2 for exponential decrease
617 }
618 
619 
620 void vimic_warnings(t_vimic *x, long n)
621 {
622  switch (n)
623  {
624  case 0:
625  if (globWarningFlag == true) post("Warnings off"); //this condition prevents postings when the module is initialized.
626  globWarningFlag = false;
627  break;
628  case 1:
629  if (globWarningFlag == false) post("Warnings on"); //this condition prevents postings when the module is initialized.
630  globWarningFlag = true;
631  break;
632  }
633 }
634 
635 void vimic_reportAll(t_vimic *x)
636 {
637  int n = 0;
638  int m = 0;
639  post("This is ViMiC for Max/MSP, (c) 2005-2012 Nils Peters, Tristan Matthews, Jonas Braasch. Version built on " __DATE__ " at " __TIME__);
640  post("renderInterval: %d",x->renderInterval);
641  post("Grainsize: %f",x->grainsize);
642  post("expected speed of sound is %f at %f degrees celsius", x->speedOfSound * x->x_sr, x->temperature);
643  x->room->mics.print();
644  x->room->print();
645  for (m = 0; m < x->room->mics.numChannels(); m++)
646  {
647  for (n = 0; n < x->numRefl; n++)
648  {
649  post("Mic %d, Refl %d, Sensi: %f", m, n, *(x->sensitivity + (x->numRefl * m) + n));
650  post("Mic %d, Refl %d, Delay: %f", m, n, *(x->delay + (x->numRefl * m) + n));
651  }
652  }
653 
654  for (m = 0; m < Properties::REFLECTIONORDER; m++)
655  post("Reflgains[%d] = %f", m, x->reflGains[m]);
656 }
657 
658 
659 
660 
661 void vimic_report(t_vimic *x, long n)
662 {
663  switch (n)
664  {
665  case 0:
666  if (globReportFlag == true) {
667  post("Report off"); //this condition prevents postings when the module is initialized.
668  }
669  globReportFlag = false;
670  break;
671  case 1:
672  if (globReportFlag == false) {
673  post("Report on"); //this condition prevents postings when the module is initialized.
674  }
675  globReportFlag = true;
676  break;
677  }
678 }
679 
680 void vimic_sourceYaw(t_vimic *x, long n)
681 {
682  x->room->sources[0].aziAngle(n);
683 }
684 
685 
686 void vimic_normalizeSensiFlag(t_vimic *x, long n)
687 {
688  switch (n)
689  {
690  case 0:
691  x->normalizeSensiFlag = false;
692  x->room->sources[0].flag(true);
693  if (x->directBang == 1) vimic_bang(x);
694  if (globReportFlag) post("Sensitivity normalization: off");
695  break;
696  case 1:
697  x->normalizeSensiFlag = true;
698  x->room->sources[0].flag(true);
699  if (x->directBang == 1) vimic_bang(x);
700  if (globReportFlag) post("Sensitivity normalization: on");
701  break;
702  }
703 }
704 
705 void vimic_minimumDelayFlag(t_vimic *x, long n)
706 {
707  switch (n)
708  {
709  case 0:
710  x->minimumDelayFlag = false;
711  x->room->sources[0].flag(true);
712  if (x->directBang == 1) vimic_bang(x);
713  if (globReportFlag) post("Minimizing time-of-fights delays: off");
714  break;
715  case 1:
716  x->minimumDelayFlag = true;
717  x->room->sources[0].flag(true);
718  if (x->directBang == 1) vimic_bang(x);
719  if (globReportFlag) post("Minimizing time-of-fights delays: on");
720  break;
721  }
722 }
723 
724 void vimic_minSensiFlag(t_vimic *x, long n)
725 {
726  switch (n)
727  {
728  case 0:
729  x->minSensiFlag = false;
730  x->room->sources[0].flag(true);
731  if (x->directBang == 1) vimic_bang(x);
732  if (globReportFlag) post("Sensitivity minimum: off");
733  break;
734  case 1:
735  x->minSensiFlag = true;
736  x->room->sources[0].flag(true);
737  if (x->directBang == 1) vimic_bang(x);
738  if (globReportFlag) post("Sensitivity minimum: on");
739  break;
740  }
741 }
742 
743 
744 
745 void vimic_sourceDirectivityFlag(t_vimic *x, long n)
746  // Source directivity flag, if true, use source directivity for sensitivity calculation
747 {
748  switch (n)
749  {
750  case 0:
751  x->room->sources[0].directivityFlag(false);
752  if (x->directBang == 1) vimic_bang(x);
753  if (globReportFlag) post("Source directivity: off");
754  break;
755  case 1:
756  x->room->sources[0].directivityFlag(true);
757  if (x->directBang == 1) vimic_bang(x);
758  if (globReportFlag) post("Source directivity: on");
759  break;
760  }
761 }
762 
763 
764 void vimic_micPolarity(t_vimic *x, long n)
765 {
766  switch (n)
767  {
768  case 1:
769  x->micPolarity = -1.0;
770  x->room->sources[0].flag(true);
771  if (x->directBang == 1) vimic_bang(x);
772  if (globReportFlag) post("Microphone polarity is unrestricted, microphone gains are between -1 and 1");
773  break;
774  case 0:
775  x->micPolarity = 0.0;
776  x->room->sources[0].flag(true);
777  if (x->directBang == 1) vimic_bang(x);
778  if (globReportFlag) post("Microphone polarity is restricted, microphone gains are between 0 and 1");
779  break;
780  default:
781  if (globWarningFlag) error("Argument must be either 1 or 0");
782  break;
783  }
784 }
785 
786 void vimic_renderintervall(t_vimic *x, long n)
787 {
788  if (n > 0)
789  {
790  x->renderInterval = n;
791  x->grainsize = 1.0 / (x->renderInterval * x->blocksize);
792  }
793  else post("renderInterval must be more than 1 blocks");
794  if (globReportFlag) post("renderInterval is %d blocks", x->renderInterval);
795 }
796 
797 void vimic_xFadeFunction(t_vimic *x, long n) //distance threshold before a x-fade is started in samples
798 {
799  x->fades->fadeFunction((Properties::fadeMode) n);
800 }
801 
802 
803 
804 void vimic_xFadeLength(t_vimic *x, long n) //fadelength in samples
805 {
806  // create a new fade-lookup table
807  if (x->fades->isActive()) post("No change, can't change fade time while actively crossfading.");
808  else x->fades->fadeLength(n);
809 }
810 
811 
812 
813 void vimic_xFadeThreshold(t_vimic *x, long n) //fadelength in samples
814  //distance threshold before a x-fade is started in samples
815 {
816  if (n >= 1) x->fades->fadeThreshold(n);
817  else post("Crossfade threshold must be >= 1");
818  if (globReportFlag) post("Crossfade threshold in samples: %d", x->fades->fadeThreshold());
819 }
820 
821 
822 void vimic_airfilter(t_vimic *x, long n)
823 {
824  for (int i = 0; i < x->numOfChannels; i++) {
825  x->room->air[i][0].cutOff(n);
826  x->room->xfadeAir[i].cutOff(n);
827  x->room->air[i][1].cutOff(n);
828  }
829  if (x->directBang == 1)
830  vimic_bang(x);
831  if (globReportFlag)
832  post("Air absorption cutoff: %ld", n);
833 }
834 
835 // Render Type
836 void vimic_renderType(t_vimic *x, long n)
837 {
838  switch (n)
839  {
840  case 0:
841  x->AudioProcType = Properties::NONE;
842  if (globReportFlag)
843  post("Audio off");
844  break;
845 
846  case 1:
847  x->AudioProcType = Properties::VIMIC_LITE;
848  if (globReportFlag)
849  post("Processing: ViMiC lite -> ViMiC with one Filter for all walls");
850  break;
851 
852  case 2:
853  x->AudioProcType = Properties::AMP_PAN;
854  if (globReportFlag)
855  post("Processing: Amplitude Panning");
856  break;
857 
858  case 3:
859  x->AudioProcType = Properties::X_FADE_LITE;
860  if (globReportFlag)
861  post("Processing: Delay w/o Pitch Shift");
862  break;
863 
864  case 4:
865  x->AudioProcType = Properties::X_FADE_XL;
866  if (globReportFlag)
867  post("Processing: Delay w/o Pitch Shift");
868  break;
869 
870  case 5:
871  x->AudioProcType = Properties::VIMIC_XL;
872  if (globReportFlag)
873  post("Processing: ViMiC XL -> ViMiC with separate Filter for each wall");
874  break;
875 
876  case 6:
877  x->AudioProcType = Properties::STATIC;
878  if (globReportFlag)
879  post("Processing: Integer delays only.");
880  break;
881 
882  default:
883  if (globWarningFlag)
884  error("Unknown rendering type.");
885  break;
886  }
887  if (x->directBang == 1) vimic_bang(x);
888 }
889 
890 
891 void vimic_getDirTable(t_vimic *x, t_symbol *s)
892 {
893  long **storage;
894  long size; // not using this, yet
895  if (!table_get(s, &storage, &size))
896  x->room->sources[0].updateDirectivity(storage);
897 
898 }
899 
900 
901 
902 
903 void vimic_highCf(t_vimic *x, long n, long freq)
904 {
905  //if (x->reflOrder > 0)
906  //{
907  if (n > 0 && n <= Properties::NUMWALLS)
908  {
909  for (int i = 0; i < x->numOfChannels; i++)
910  {
911  if (n == Properties::LEFT) // left filter controls filtering for lite sim
912  {
913  for (int filterNum = 0; filterNum < 2; filterNum++) // set all filters to match
914  x->room->xfadeWalls[i][filterNum].highShelfFrequency(freq);
915  }
916  x->room->walls[i][n - 1].highShelfFrequency(freq);
917 
918  //if (x->reflOrder == 2)
919  x->room->walls[i][n + Properties::NUMWALLS - 1].highShelfFrequency(freq);
920  }
921  }
922  else if (globWarningFlag) post("Invalid wall index %d", n);
923  if (x->directBang == 1) vimic_bang(x);
924  if (globReportFlag) post("Wall %d high shelf centre frequency: %ld", n, freq);
925  //}
926  //else if (globWarningFlag) error("No filtering for reflection order of 0.");
927 }
928 
929 
930 void vimic_lowCf(t_vimic *x, long n, long freq)
931 {
932  //if (x->reflOrder > 0)
933  //{
934  if (n > 0 && n <= Properties::NUMWALLS)
935  {
936  for (int i = 0; i < x->numOfChannels; i++)
937  {
938  if (n == Properties::LEFT) // left filter controls filtering for lite sim
939  {
940  for (int filterNum = 0; filterNum < 2; filterNum++) // set all filters to match
941  x->room->xfadeWalls[i][filterNum].lowShelfFrequency(freq);
942  }
943  x->room->walls[i][n - 1].lowShelfFrequency(freq);
944  //if (x->reflOrder == 2)
945  x->room->walls[i][n + Properties::NUMWALLS - 1].lowShelfFrequency(freq);
946  }
947  }
948  else if (globWarningFlag) post("Invalid wall index %d", n);
949  if (x->directBang == 1) vimic_bang(x);
950  if (globReportFlag) post("Wall %d low shelf centre frequency: %ld", n, freq);
951  //}
952  //else if (globWarningFlag) error("No filtering for reflection order of 0.");
953 }
954 
955 void vimic_lowAbsorption(t_vimic *x, t_symbol *s, short argc, t_atom *argv)
956 {
957  //if (x->reflOrder > 0)
958  //{
959  long b = 0;
960 
961  if (argc == 2)
962  {
963  if (argv[0].a_type == A_LONG)
964  {
965  b = argv[0].a_w.w_long;
966  if (argv[1].a_type == A_FLOAT)
967  {
968  if (b > 0 && b <= Properties::NUMWALLS)
969  {
970  for (int i = 0; i < x->numOfChannels; i++)
971  {
972  if (b == Properties::LEFT)
973  {
974  for (int filterNum = 0; filterNum < 2; filterNum++) // set all filters to match
975  x->room->xfadeWalls[i][filterNum].lowGain(argv[1].a_w.w_float);
976  }
977 
978  x->room->walls[i][b - 1].lowGain(argv[1].a_w.w_float);
979 
980  //if (x->reflOrder == 2)
981  //{
982  x->room->walls[i][b + Properties::NUMWALLS - 1].lowGain(argv[1].a_w.w_float);
983  //}
984  }
985  }
986  else if (globWarningFlag) post("Invalid wall index %d", b);
987 
988  if (globReportFlag) post("Wall %d low gain: %f", b, argv[1].a_w.w_float);
989  }
990  }
991  }
992  else if (globWarningFlag) error("Incorrect # of args.");
993  if (x->directBang == 1) vimic_bang(x);
994  //}
995  //else if (globWarningFlag) error("No filtering for reflection order of 0.");
996 }
997 
998 
999 
1000 
1001 
1002 void vimic_midAbsorption(t_vimic *x, t_symbol *s, short argc, t_atom *argv)
1003 {
1004  //if (x->reflOrder > 0)
1005  //{
1006  long b = 0;
1007 
1008  if (argc == 2)
1009  {
1010  if (argv[0].a_type == A_LONG)
1011  {
1012  b = argv[0].a_w.w_long;
1013  if (argv[1].a_type == A_FLOAT)
1014  {
1015  if (b > 0 && b <= Properties::NUMWALLS)
1016  {
1017  for (int i = 0; i < x->numOfChannels; i++)
1018  {
1019  if (b == Properties::LEFT)
1020  {
1021  for (int filterNum = 0; filterNum < 2; filterNum++)
1022  x->room->xfadeWalls[i][filterNum].midGain(argv[1].a_w.w_float);
1023  }
1024 
1025  x->room->walls[i][b - 1].midGain(argv[1].a_w.w_float);
1026 
1027  //if (x->reflOrder == 2)
1028  //{
1029  x->room->walls[i][b + Properties::NUMWALLS - 1].midGain(argv[1].a_w.w_float);
1030  //}
1031  }
1032  }
1033  else if (globWarningFlag) post("Invalid wall index %d", b);
1034  if (globReportFlag) post("Wall %d mid gain: %f", b, argv[1].a_w.w_float);
1035  }
1036  }
1037  }
1038  else if (globWarningFlag)
1039  error("Incorrect # of args.");
1040  //}
1041  //else if (globWarningFlag)
1042  // error("No filtering for reflection order of 0.");
1043 }
1044 
1045 
1046 void vimic_highAbsorption(t_vimic *x, t_symbol *s, short argc, t_atom *argv)
1047 {
1048  // if (x->reflOrder > 0)
1049  // {
1050  long b = 0;
1051 
1052  if (argc == 2)
1053  {
1054  if (argv[0].a_type == A_LONG)
1055  {
1056  b = argv[0].a_w.w_long;
1057 
1058  if (argv[1].a_type == A_FLOAT)
1059  {
1060  if (b > 0 && b <= Properties::NUMWALLS)
1061  {
1062  for (int i = 0; i < x->numOfChannels; i++)
1063  {
1064  if (b == Properties::LEFT) // left filter controls filtering for lite sim
1065  {
1066  for (int filterNum = 0; filterNum < 2; filterNum++) // set all filters to match
1067  x->room->xfadeWalls[i][filterNum].highGain(argv[1].a_w.w_float);
1068  }
1069 
1070  x->room->walls[i][b - 1].highGain(argv[1].a_w.w_float);
1071 
1072  //if (x->reflOrder == 2)
1073  //{
1074  //post("b: %d", b);
1075  x->room->walls[i][b + Properties::NUMWALLS - 1].highGain(argv[1].a_w.w_float);
1076  //}
1077  }
1078  }
1079  else if (globWarningFlag) post("Invalid wall index %d", b);
1080 
1081  if (globReportFlag) post("Wall %d high gain: %f", b, argv[1].a_w.w_float);
1082  }
1083  }
1084  }
1085  else if (globWarningFlag) error("Incorrect # of args.");
1086  //}
1087  //else if (globWarningFlag) error("No filtering for reflection order of 0.");
1088 }
1089 
1090 void vimic_wallFilter(t_vimic *x, t_symbol *s, short argc, t_atom *argv)
1091 {
1092  // if (x->reflOrder > 0)
1093  // {
1094  long b = 0;
1095 
1096  if (argc == 6)
1097  {
1098  if (argv[0].a_type == A_LONG)
1099  {
1100  b = argv[0].a_w.w_long;
1101 
1102  if ((argv[1].a_type == A_FLOAT) && (argv[2].a_type == A_FLOAT) && (argv[3].a_type == A_FLOAT) && (argv[4].a_type == A_LONG) && (argv[5].a_type == A_LONG))
1103  {
1104  if (b > 0 && b <= Properties::NUMWALLS)
1105  {
1106  for (int i = 0; i < x->numOfChannels; i++)
1107  {
1108  if (b == Properties::LEFT) // left filter controls filtering for lite sim
1109  {
1110  for (int filterNum = 0; filterNum < 2; filterNum++)
1111  { // set all filters to match
1112  x->room->xfadeWalls[i][filterNum].lowGain(argv[1].a_w.w_float);
1113  x->room->xfadeWalls[i][filterNum].midGain(argv[2].a_w.w_float);
1114  x->room->xfadeWalls[i][filterNum].highGain(argv[3].a_w.w_float);
1115  x->room->xfadeWalls[i][filterNum].lowShelfFrequency(argv[4].a_w.w_long);
1116  x->room->xfadeWalls[i][filterNum].highShelfFrequency(argv[5].a_w.w_long);
1117  }
1118  }
1119 
1120  x->room->walls[i][b - 1].lowGain(argv[1].a_w.w_float);
1121  x->room->walls[i][b - 1].midGain(argv[2].a_w.w_float);
1122  x->room->walls[i][b - 1].highGain(argv[3].a_w.w_float);
1123  x->room->walls[i][b - 1].lowShelfFrequency(argv[4].a_w.w_long);
1124  x->room->walls[i][b - 1].highShelfFrequency(argv[5].a_w.w_long);
1125 
1126 
1127  //if (x->reflOrder == 2)
1128  //{
1129  x->room->walls[i][b + Properties::NUMWALLS - 1].lowGain(argv[1].a_w.w_float);
1130  x->room->walls[i][b + Properties::NUMWALLS - 1].midGain(argv[2].a_w.w_float);
1131  x->room->walls[i][b + Properties::NUMWALLS - 1].highGain(argv[3].a_w.w_float);
1132  x->room->walls[i][b + Properties::NUMWALLS - 1].lowShelfFrequency(argv[4].a_w.w_long);
1133  x->room->walls[i][b + Properties::NUMWALLS - 1].highShelfFrequency(argv[5].a_w.w_long);
1134  //}
1135  }
1136  }
1137  else if (globWarningFlag) post("Invalid wall index %d", b);
1138  if (globReportFlag) post("Wall %d lowGain %f, midGain: %f, highGain: %f, lowShelfFreq %f, highShelfFreq %f", b, argv[1].a_w.w_float, argv[2].a_w.w_float, argv[3].a_w.w_float, argv[4].a_w.w_float, argv[5].a_w.w_float);
1139  }
1140  else if (globWarningFlag) error("Incorrect syntax. wallFilter index <int> lowGain <float> midGain <float> highGain <float> lowShelfFrequency <int> highShelfFrequency <int>");
1141  }
1142  }
1143  else if (globWarningFlag) error("Incorrect # of args.");
1144  // }
1145  // else if (globWarningFlag) error("No filtering for reflection order of 0.");
1146 }
1147 
1148 
1149 
1150 /*void vimic_anything(t_vimic *x, t_symbol *s, short argc, t_atom *argv)
1151  { // leftovers
1152 
1153  if (s == gensym("/MicCenterDistance"))
1154  {
1155  if (argc == 1)
1156  {
1157  if (argv[0].a_type == A_FLOAT) // First variable is Center Distance coordinate
1158  x->room->mics.centerDistance(argv[0].a_w.w_float); // renders all mics
1159  }
1160  else if (globWarningFlag)
1161  error("Incorrect # of args.");
1162  }
1163 
1164  else if (s == gensym("/HeadAngle"))
1165  {
1166  if (argc == 1)
1167  {
1168  if (argv[0].a_type == A_FLOAT) // variable is head angle in deg
1169  {
1170  x->headAngle = argv[0].a_w.w_float;
1171  if (globReportFlag)
1172  post("/HeadAngle= %f",x->headAngle);
1173  }
1174  }
1175  else if (globWarningFlag)
1176  error("Incorrect # of args.");
1177  }
1178  }*/
1179 
1180 
1181 void vimic_bang(t_vimic *x)
1182 {
1183  int m; // counter
1184  bool grainCounterFlag = false;
1185 
1186  if (x->room->mirrorFlag())
1187  {
1188  grainCounterFlag = true;
1189  x->room->renderMirrors();
1190  }
1191 
1192 
1193  //if (x->reflOrder < 3)
1194  //{
1195  //critical_enter(0);
1196  for (m = 0; m < x->numOfChannels; m++)
1197  {
1198  if (x->room->sources[0].flag() || x->room->mics[m].flag() || x->room->mics.flag() || x->reflGainFlag)
1199  {
1200  grainCounterFlag = true;
1201  vimic_mirrors(x->sensitivity + x->numRefl * m,
1202  x->delay + x->numRefl * m,
1203  &x->room->mics[m],
1204  x->room->mirrors,
1205  &x->room->sources[0],
1206  x->invSpeedOfSound,
1207  x->numRefl, x->AudioProcType, x->currentDelay + x->numRefl * m, x->reflGains, x->fades, x->micPolarity, x->distModel);
1208  //post("mirrors: Mic number %d has xpos of %f", m, x->room->mics[m].xPos());
1209  }
1210  x->room->mics[m].flag(false);
1211  }
1212  x->room->mics.flag(false);
1213  //critical_exit(0);
1214  //}
1215 
1216 
1217  if (grainCounterFlag) // something has changed
1218  {
1219  if (x->minSensiFlag)
1220  { //critical_enter(0);
1221  for (int i = 0; i < x->bufSz; i++)
1222  vimic_floorSensi(x->sensitivity + i, x->minSensi);
1223  //critical_exit(0);
1224  }
1225 
1226  if (x->normalizeSensiFlag) {
1227  //critical_enter(0);
1228  double invSqrtSumSensi = vimic_invSqrtSumSensi(x->sensitivity, x->bufSz);
1229  for (int i = 0; i < x->bufSz; i++)
1230  vimic_normalizeSensi(x->sensitivity + i, invSqrtSumSensi);
1231  //critical_exit(0);
1232  }
1233 
1234  if (x->minimumDelayFlag) {
1235  double minDelay = vimic_findMinDelayValue(x->delay, x->bufSz);
1236  for (int i = 0; i < x->bufSz; i++)
1237  vimic_minimizeDelay(x->delay + i, minDelay);
1238  }
1239 
1240  //critical_enter(0);
1241  for (m = 0; m < x->bufSz; m++) {
1242  x->delGrain[m] = ((double) x->delay[m] - x->currentDelay[m]) * x->grainsize; // copy old values into buffer
1243 #ifndef __INTEL_COMPILER
1244  TTZeroDenormal(x->delGrain[m]); // FIXME: necessary?
1245 #endif
1246  x->sensiGrain[m] = (x->sensitivity[m] - x->currentSensitivity[m]) * x->grainsize; // copy old values into buffer
1247 #ifndef __INTEL_COMPILER
1248  TTZeroDenormal(x->sensiGrain[m]);
1249 #endif
1250  }
1251  //critical_exit(0);
1252  x->grainCounter = 0;
1253  }
1254  x->room->sources[0].flag(false);
1255  x->reflGainFlag = false;
1256 }
1257 
1258 #pragma warning(push)
1259 #pragma warning(disable: 4312; disable : 4700)
1260 t_int* vimic_perform(t_int *w)// is that good to initialize all the variable in the perform function?
1261 {
1262  t_vimic *x = (t_vimic *)(w[1]);
1263  int numChannels = x->numOfChannels;
1264 
1265  if (x->x_obj.z_disabled) // if muted, return
1266  return (w + 4 + numChannels);
1267 
1268  t_sample *in;
1269 
1270  // TM: allocate based on number of channels now.
1271  t_sample *out[Properties::MAXNUMCHANNELS];
1272  bool micGainNonZero[Properties::MAXNUMCHANNELS];
1273 
1274  int n = (t_int)(w[3 + x->numOfChannels]); //can be calculated outside?? maybe?
1275  int phase = x->c_phase;
1276  int blocksize = n; // it is also good to have 1_over_blocksize calculated to ge rid of the divisions
1277  int renderInterval = x->renderInterval;
1278  int GrainCounter = x->grainCounter;
1279  int numOfRefl = x->numRefl;
1280  int maxDynRefl = x->maxDynRefl;
1281  int reflOrderIndex = 0;
1282  double *reflGains = x->reflGains;
1283  double *currentDelay = x->currentDelay;
1284  double *currentSensitivity = x->currentSensitivity;
1285  double *delGrain = x->delGrain;
1286  double *sensiGrain = x->sensiGrain;
1287  double *bp = x->c_vec + phase;
1288  double *ep = x->c_vec + Properties::DELAYSIZE;
1289  double frac;
1290  int idelay, idelayOld;
1291  double newSamp, oldSamp, newReflSamps, oldReflSamps, reflSamps = 0.0;
1292  int sampPos = 0;
1293  double *delay = x->delay;
1294  double *sensitivity = x->sensitivity;
1295  int numwallsMinusOne = Properties::NUMWALLS - 1; //optimization
1296  int numOfReflTimesK;
1297  HiMidLow **walls = x->room->walls;
1298  LowPass **air = x->room->air;
1299 
1300  // for Xfade
1301  HiMidLow **xfadeWalls = x->room->xfadeWalls;
1302  LowPass *xfadeAir = x->room->xfadeAir;
1303 
1304  CrossFadeQueue *fades = x->fades;
1305 
1306  in = (t_sample *)(w[2]);
1307 
1308  for (int i = 0; i < numChannels; ++i)
1309  {
1310  out[i] = (t_sample *)(w[3 + i]);
1311  if (x->room->mics[i].gain() != 0.0)
1312  micGainNonZero[i] = true;
1313  else
1314  micGainNonZero[i] = false;
1315  }
1316 
1317  switch (x->AudioProcType)
1318  {
1319  case Properties::VIMIC_LITE: // ViMiC wtih reduced Filtering
1320 
1321  if (GrainCounter < renderInterval)
1322  {
1323  double a, b, c, d, cminusb; // variables for fractional delay line
1324  while (n--)
1325  {
1326  // Write to delay line
1327  double f = *in++; // get input
1328  *(bp) = f;
1329  *(bp + Properties::DELAYSIZE) = f;
1330 
1331  for (int k = 0; k < numChannels; ++k)
1332  {
1333  *out[k] = 0.0;
1334  reflSamps = 0.0;
1335  numOfReflTimesK = numOfRefl * k;
1336 
1337  if (micGainNonZero[k])
1338  { // TM: if x->maxDynRefl is always same as x->numRefl, why is it necessary?
1339  for (int reflNum = maxDynRefl - 1; reflNum >= Properties::DIRECT; --reflNum)
1340  {
1341  reflOrderIndex = reflNum + numOfReflTimesK;
1342 
1343  *(currentDelay + reflOrderIndex) += *(delGrain + reflOrderIndex); // TM: Changed
1344  *(currentSensitivity + reflOrderIndex) += *(sensiGrain + reflOrderIndex);
1345 
1346  if (*(currentSensitivity + reflOrderIndex) != 0.0)
1347  {
1348  idelay = *(currentDelay + reflOrderIndex) + 0.5;
1349  frac = *(currentDelay + reflOrderIndex) - (double) idelay; // fractional part of delay value
1350  sampPos = Properties::DELAYSIZE - idelay; // was sampPos = DELAYSIZE;
1351 
1352  d = *(bp + sampPos - 3);
1353  c = *(bp + sampPos - 2);
1354  b = *(bp + sampPos - 1);
1355  a = *(bp + sampPos);
1356  cminusb = c - b;
1357 
1358  switch (reflNum)
1359  {
1360  case 0: // sum direct sound with reflections
1361  *out[k] = (*(currentSensitivity + reflOrderIndex) * (b + frac * (cminusb - 0.1666667 * (1.0 - frac)
1362  * ((d - a - 3.0 * cminusb) * frac + (d + 2.0 * a - 3.0 * b))))) + reflSamps;
1363  break;
1364  case 1: // sum 1st order reflections (potentially with 2nd order reflections)
1365  reflSamps += *(currentSensitivity + reflOrderIndex)
1366  * (b + frac * (cminusb - 0.1666667 * (1.0 - frac) * ((d - a - 3.0 * cminusb)
1367  * frac + (d + 2.0 * a - 3.0 * b))));
1368  reflSamps = air[k][0].tick(walls[k][0].tick(reflSamps));
1369  break;
1370  case 7: // sum 2nd order reflections
1371  reflSamps += *(currentSensitivity + reflOrderIndex)
1372  * (b + frac * (cminusb - 0.1666667 * (1.0 - frac) * ((d - a - 3.0 * cminusb)
1373  * frac + (d + 2.0 * a - 3.0 * b))));
1374  reflSamps = walls[k][6].tick(reflSamps);
1375  break;
1376  default:
1377  reflSamps += *(currentSensitivity + reflOrderIndex)
1378  * (b + frac * (cminusb - 0.1666667 * (1.0 - frac) * ((d - a - 3.0 * cminusb)
1379  * frac + (d + 2.0 * a - 3.0 * b))));
1380  break;
1381  }
1382  }
1383  else
1384  {//post("here %d",reflNum);
1385  switch (reflNum)
1386  {
1387  case 1: // sum 1st order reflections (potentially with 2nd order reflections)
1388  reflSamps = air[k][0].tick(walls[k][0].tick(reflSamps));
1389  break;
1390  case 7: // sum 2nd order reflections
1391  reflSamps = walls[k][6].tick(reflSamps);
1392  break;
1393  }
1394 
1395  }
1396  }
1397  }
1398  out[k]++;
1399  }
1400  bp++;
1401  } // end of while
1402  for (int reflNum = 0 ; reflNum < numChannels * numOfRefl ; ++reflNum) //We need to update the Sensi and Delay vector so that in case for a new bang, the correct grains can be calculated
1403  {
1404  x->currentSensitivity[reflNum] = *(currentSensitivity + reflNum);
1405  x->currentDelay[reflNum] = *(currentDelay + reflNum);
1406  }
1407  }
1408  else // steady state, non-fractional delay, constant values
1409  {
1410  while (n--)
1411  {
1412  //Write to delay line
1413  double f = *in++; // get input
1414  *(bp) = f;
1415  *(bp + Properties::DELAYSIZE) = f;
1416 
1417  for (int k = 0; k < numChannels; ++k)
1418  {
1419  numOfReflTimesK = numOfRefl * k;
1420  *out[k] = 0.0;
1421  reflSamps = 0.0;
1422  if (micGainNonZero[k])
1423  {
1424  for (int reflNum = numOfRefl - 1; reflNum >= Properties::DIRECT; --reflNum)
1425  {
1426  reflOrderIndex = reflNum + numOfReflTimesK;
1427  idelay = *(currentDelay + reflOrderIndex) +1.5; //was - 0.5; but I think that we cause a general delay of 2 samples due to the interpolation, so we have to respect that in the static method too, otherwise we will have small jumps of 2 samples back & forth
1428 
1429  switch (reflNum)
1430  {
1431  case 0:
1432  *out[k] = *(currentSensitivity + reflOrderIndex) * *(bp + Properties::DELAYSIZE - idelay) + reflSamps;
1433  break;
1434 
1435  case 1:
1436  reflSamps += *(currentSensitivity + reflOrderIndex) * *(bp + Properties::DELAYSIZE - idelay);
1437  reflSamps = air[k][0].tick(walls[k][0].tick(reflSamps));
1438  break;
1439 
1440  case 7:
1441  reflSamps += *(currentSensitivity + reflOrderIndex) * *(bp + Properties::DELAYSIZE - idelay);
1442  reflSamps = walls[k][6].tick(reflSamps);
1443  break;
1444 
1445  default:
1446  reflSamps += *(currentSensitivity + reflOrderIndex) * *(bp + Properties::DELAYSIZE - idelay);
1447  break;
1448  }
1449 
1450  }
1451  }
1452  out[k]++;
1453  }
1454  bp++;
1455  } // end of while
1456  }
1457 
1458  if (bp >= ep) // return pointer to start when it arrives at the end. TM: changed == to >=
1459  x->c_phase = 0;
1460  //NP: I think this condition has to be checked only at the end of a block (control-rate) and not at sample rate.
1461  else
1462  x->c_phase = phase + blocksize;
1463 
1464  if (x->grainCounter < renderInterval)
1465  x->grainCounter++;
1466  break;
1467  ////////////////////////////////////////////////////////////////////////////////
1468  case Properties::VIMIC_XL: // reflections are filtered
1469  double frontSamps, rearSamps, floorSamps, ceilSamps, filterInputSamp;
1470  if (GrainCounter < renderInterval) // transitional state with fractional delay and interpolated values
1471  {
1472  double a, b, c, d, cminusb; // variables for fractional delay line
1473  while (n--)
1474  {
1475  double f = *in++; // get input
1476  *(bp) = f; // write to delay line
1477  *(bp + Properties::DELAYSIZE) = f;
1478 
1479  for (int k = 0; k < numChannels; ++k)
1480  {
1481  *out[k] = 0.0;
1482  frontSamps = rearSamps = floorSamps = ceilSamps = reflSamps = filterInputSamp = 0.0;
1483  numOfReflTimesK = numOfRefl * k;
1484  if (micGainNonZero[k])
1485  {
1486  for (int reflNum = maxDynRefl - 1; reflNum >= 0; --reflNum) // TM: if x->maxDynRefl is always same as x->numRefl, why is it necessary?
1487  {
1488  reflOrderIndex = reflNum + numOfReflTimesK;
1489  *(currentDelay + reflOrderIndex) += *(delGrain + reflOrderIndex); // TM: Changed
1490  *(currentSensitivity + reflOrderIndex) += *(sensiGrain + reflOrderIndex);
1491 
1492  if (*(sensitivity + reflOrderIndex) != 0.0)
1493  {
1494  idelay = 0.5 + *(currentDelay + reflOrderIndex);
1495  frac = *(currentDelay + reflOrderIndex) - (double) idelay; // fractional part of delay value
1496  sampPos = Properties::DELAYSIZE - idelay; // was sampPos = Properties::DELAYSIZE;
1497 
1498  d = *(bp + sampPos - 3);
1499  c = *(bp + sampPos - 2);
1500  b = *(bp + sampPos - 1);
1501  a = *(bp + sampPos);
1502  cminusb = c - b;
1503 
1504  filterInputSamp = *(currentSensitivity + reflOrderIndex)
1505  * (b + frac * (cminusb - 0.1666667 * (1.0 - frac) * ((d - a - 3.0 * cminusb) * frac + (d + 2.0 * a - 3.0 * b))));
1506 
1507  switch (reflNum) // TODO: is there a cleaner and clear way of doing this that is as fast?
1508  {
1509  case Properties::FRONT_FLOOR:
1510  floorSamps += walls[k][Properties::FRONT + numwallsMinusOne].tick(filterInputSamp);
1511  break;
1512  case Properties::REAR_FLOOR:
1513  floorSamps += walls[k][Properties::REAR + numwallsMinusOne].tick(filterInputSamp);
1514  break;
1515  case Properties::LEFT_FLOOR:
1516  floorSamps += walls[k][Properties::LEFT + numwallsMinusOne].tick(filterInputSamp);
1517  break;
1518  case Properties::RIGHT_FLOOR:
1519  floorSamps += walls[k][Properties::RIGHT + numwallsMinusOne].tick(filterInputSamp);
1520  break;
1521 
1522  case Properties::LEFT_CEILING:
1523  ceilSamps += walls[k][Properties::LEFT + numwallsMinusOne].tick(filterInputSamp);
1524  break;
1525  case Properties::RIGHT_CEILING:
1526  ceilSamps += walls[k][Properties::RIGHT + numwallsMinusOne].tick(filterInputSamp);
1527  break;
1528  case Properties::FRONT_CEILING:
1529  ceilSamps += walls[k][Properties::FRONT + numwallsMinusOne].tick(filterInputSamp);
1530  break;
1531  case Properties::REAR_CEILING:
1532  ceilSamps += walls[k][Properties::REAR + numwallsMinusOne].tick(filterInputSamp);
1533  break;
1534 
1535  case Properties::LEFT_FRONT:
1536  frontSamps += walls[k][Properties::LEFT + numwallsMinusOne].tick(filterInputSamp);
1537  break;
1538  case Properties::RIGHT_FRONT:
1539  frontSamps += walls[k][Properties::RIGHT + numwallsMinusOne].tick(filterInputSamp);
1540  break;
1541 
1542  case Properties::LEFT_REAR:
1543  rearSamps += walls[k][Properties::LEFT + numwallsMinusOne].tick(filterInputSamp);
1544  break;
1545  case Properties::RIGHT_REAR:
1546  rearSamps += walls[k][Properties::RIGHT + numwallsMinusOne].tick(filterInputSamp);
1547  break;
1548 
1549  case Properties::AIR:
1550  *out[k] += filterInputSamp;
1551  break;
1552 
1553  //after one reflection
1554 
1555  case Properties::LEFT:// after one reflection
1556  reflSamps += walls[k][0].tick(filterInputSamp); // write first order reflection to output [Properties::LEFT - 1]
1557  *out[k] = air[k][0].tick(reflSamps); // reflections are filtered by air absorption LPF
1558  break;
1559 
1560  case Properties::RIGHT:
1561  reflSamps += walls[k][1].tick(filterInputSamp); // write first order reflection to output [Properties::RIGHT - 1]
1562  break;
1563 
1564 
1565  case Properties::FRONT:
1566  frontSamps += filterInputSamp;
1567  reflSamps += walls[k][2].tick(frontSamps); // write reflections to output [Properties::FRONT - 1]
1568  break;
1569 
1570  case Properties::REAR:
1571  rearSamps += filterInputSamp;
1572  reflSamps += walls[k][3].tick(rearSamps); // write reflections to output [Properties::REAR - 1]
1573  break;
1574 
1575  case Properties::FLOOR:
1576  floorSamps += filterInputSamp;
1577  reflSamps += walls[k][4].tick(floorSamps); // write reflections to output [FLOOR - 1]
1578  break;
1579 
1580  case Properties::CEILING:
1581  ceilSamps += filterInputSamp;
1582  reflSamps += walls[k][5].tick(ceilSamps); // write first order reflection to output [CEILING - 1]
1583  break;
1584  }
1585  }
1586  else
1587  {
1588  switch (reflNum) // TODO: is there a cleaner and clear way of doing this that is as fast?
1589  {
1590  case Properties::FRONT_FLOOR:
1591  floorSamps += walls[k][Properties::FRONT + numwallsMinusOne].tick(filterInputSamp);
1592  break;
1593  case Properties::REAR_FLOOR:
1594  floorSamps += walls[k][Properties::REAR + numwallsMinusOne].tick(filterInputSamp);
1595  break;
1596  case Properties::LEFT_FLOOR:
1597  floorSamps += walls[k][Properties::LEFT + numwallsMinusOne].tick(filterInputSamp);
1598  break;
1599  case Properties::RIGHT_FLOOR:
1600  floorSamps += walls[k][Properties::RIGHT + numwallsMinusOne].tick(filterInputSamp);
1601  break;
1602  case Properties::LEFT_CEILING:
1603  ceilSamps += walls[k][Properties::LEFT + numwallsMinusOne].tick(filterInputSamp);
1604  break;
1605  case Properties::RIGHT_CEILING:
1606  ceilSamps += walls[k][Properties::RIGHT + numwallsMinusOne].tick(filterInputSamp);
1607  break;
1608  case Properties::FRONT_CEILING:
1609  ceilSamps += walls[k][Properties::FRONT + numwallsMinusOne].tick(filterInputSamp);
1610  break;
1611  case Properties::REAR_CEILING:
1612  ceilSamps += walls[k][Properties::REAR + numwallsMinusOne].tick(filterInputSamp);
1613  break;
1614 
1615  case Properties::LEFT_FRONT:
1616  frontSamps += walls[k][Properties::LEFT + numwallsMinusOne].tick(filterInputSamp);
1617  break;
1618  case Properties::RIGHT_FRONT:
1619  frontSamps += walls[k][Properties::RIGHT + numwallsMinusOne].tick(filterInputSamp);
1620  break;
1621 
1622  case Properties::LEFT_REAR:
1623  rearSamps += walls[k][Properties::LEFT + numwallsMinusOne].tick(filterInputSamp);
1624  break;
1625  case Properties::RIGHT_REAR:
1626  rearSamps += walls[k][Properties::RIGHT + numwallsMinusOne].tick(filterInputSamp);
1627  break;
1628 
1629  /*case AIR:
1630  *out[k] += filterInputSamp;
1631  break;*/
1632 
1633  //after one reflection
1634 
1635  case Properties::LEFT:// after one reflection
1636  reflSamps += walls[k][0].tick(filterInputSamp); // write first order reflection to output [Properties::LEFT - 1]
1637  *out[k] += air[k][0].tick(reflSamps); // reflections are filtered by air absorption LPF
1638  break;
1639  case Properties::RIGHT:
1640  reflSamps += walls[k][1].tick(filterInputSamp); // write first order reflection to output [Properties::RIGHT - 1]
1641  break;
1642 
1643 
1644  case Properties::FRONT:
1645  //frontSamps += filterInputSamp;
1646  reflSamps += walls[k][2].tick(frontSamps); // write reflections to output [Properties::FRONT - 1]
1647  break;
1648 
1649  case Properties::REAR:
1650  //rearSamps += filterInputSamp;
1651  reflSamps += walls[k][3].tick(rearSamps); // write reflections to output [Properties::REAR - 1]
1652  break;
1653 
1654  case Properties::FLOOR:
1655  //floorSamps += filterInputSamp;
1656  reflSamps += walls[k][4].tick(floorSamps); // write reflections to output [FLOOR - 1]
1657  break;
1658 
1659  case Properties::CEILING:
1660  //ceilSamps += filterInputSamp;
1661  reflSamps += walls[k][5].tick(ceilSamps); // write first order reflection to output [CEILING - 1]
1662  break;
1663  }
1664  }
1665  }
1666  }
1667  out[k]++;
1668  }
1669  bp++;
1670  } // end of while
1671 
1672  for (int reflNum = 0 ; reflNum < numChannels * numOfRefl ; ++reflNum)
1673  { //We need to update the Sensi and Delay vector so that in case for a new bang, the correct grains can be calculated
1674  x->currentSensitivity[reflNum] = *(currentSensitivity + reflNum);
1675  x->currentDelay[reflNum] = *(currentDelay + reflNum);
1676  }
1677  }
1678  else // steady state, non-fractional delay, constant values
1679  {
1680  while (n--)
1681  {
1682  //Write to delay line
1683 
1684  double f = *in++; // get input
1685 
1686  *(bp) = f; // Direct sound
1687  *(bp + Properties::DELAYSIZE) = f; // first order reflections
1688 
1689  for (int k = 0; k < numChannels; ++k)
1690  {
1691  *out[k] = 0.0;
1692  frontSamps = rearSamps = floorSamps = ceilSamps = reflSamps = filterInputSamp = 0.0;
1693  numOfReflTimesK = numOfRefl * k;
1694  if (micGainNonZero[k])
1695  {
1696  for (int reflNum = numOfRefl - 1; reflNum >= 0; --reflNum)
1697  {
1698  if (reflGains[0] != 0.0 || reflGains[1] != 0.0 || reflGains[2] != 0.0) // 0 for direct, 1 for 1st order, 2 for snd order
1699  {
1700  reflOrderIndex = reflNum + numOfReflTimesK;
1701  idelay = *(currentDelay + reflOrderIndex) +0.5;
1702  filterInputSamp = *(currentSensitivity + reflOrderIndex) * *(bp + Properties::DELAYSIZE - idelay);
1703 
1704  switch (reflNum) // TODO: is there a cleaner but also clear way of doing this that is as fast?
1705  {
1706  case Properties::FRONT_FLOOR:
1707  floorSamps += walls[k][Properties::FRONT + numwallsMinusOne].tick(filterInputSamp);
1708  break;
1709  case Properties::REAR_FLOOR:
1710  floorSamps += walls[k][Properties::REAR + numwallsMinusOne].tick(filterInputSamp);
1711  break;
1712  case Properties::LEFT_FLOOR:
1713  floorSamps += walls[k][Properties::LEFT + numwallsMinusOne].tick(filterInputSamp);
1714  break;
1715  case Properties::RIGHT_FLOOR:
1716  floorSamps += walls[k][Properties::RIGHT + numwallsMinusOne].tick(filterInputSamp);
1717  break;
1718  case Properties::LEFT_CEILING:
1719  ceilSamps += walls[k][Properties::LEFT + numwallsMinusOne].tick(filterInputSamp);
1720  break;
1721  case Properties::RIGHT_CEILING:
1722  ceilSamps += walls[k][Properties::RIGHT + numwallsMinusOne].tick(filterInputSamp);
1723  break;
1724  case Properties::FRONT_CEILING:
1725  ceilSamps += walls[k][Properties::FRONT + numwallsMinusOne].tick(filterInputSamp);
1726  break;
1727  case Properties::REAR_CEILING:
1728  ceilSamps += walls[k][Properties::REAR + numwallsMinusOne].tick(filterInputSamp);
1729  break;
1730 
1731  case Properties::LEFT_FRONT:
1732  frontSamps += walls[k][Properties::LEFT + numwallsMinusOne].tick(filterInputSamp);
1733  break;
1734  case Properties::RIGHT_FRONT:
1735  frontSamps += walls[k][Properties::RIGHT + numwallsMinusOne].tick(filterInputSamp);
1736  break;
1737 
1738  case Properties::LEFT_REAR:
1739  rearSamps += walls[k][Properties::LEFT + numwallsMinusOne].tick(filterInputSamp);
1740  break;
1741  case Properties::RIGHT_REAR:
1742  rearSamps += walls[k][Properties::RIGHT + numwallsMinusOne].tick(filterInputSamp);
1743  break;
1744 
1745  case Properties::AIR: // filtered direct sound
1746  *out[k] += filterInputSamp;
1747  break;
1748 
1749  // after one reflection
1750  case Properties::LEFT:
1751  reflSamps += walls[k][0].tick(filterInputSamp); // sum first order reflections [Properties::LEFT - 1]
1752  *out[k] += air[k][0].tick(reflSamps); // reflections are filtered by air absorption LPF
1753  break;
1754 
1755  case Properties::RIGHT:
1756  reflSamps += walls[k][1].tick(filterInputSamp); // sum first order reflections [Properties::RIGHT - 1]
1757  break;
1758 
1759 
1760  case Properties::FRONT:
1761  frontSamps += filterInputSamp;
1762  reflSamps += walls[k][2].tick(frontSamps); // write reflections to output [Properties::FRONT - 1]
1763  break;
1764 
1765  case Properties::REAR:
1766  rearSamps += filterInputSamp;
1767  reflSamps += walls[k][3].tick(rearSamps); // write reflections to output [Properties::REAR - 1]
1768  break;
1769 
1770  case Properties::FLOOR:
1771  floorSamps += filterInputSamp;
1772  reflSamps += walls[k][4].tick(floorSamps); // write reflections to output [FLOOR - 1]
1773  break;
1774 
1775  case Properties::CEILING:
1776  ceilSamps += filterInputSamp;
1777  reflSamps += walls[k][5].tick(ceilSamps); // write first order reflection to output [CEILING - 1]
1778  break;
1779  }
1780  }
1781  }
1782  }
1783  out[k]++;
1784  }
1785  bp++;
1786  } // end of while
1787 
1788 
1789  }
1790  if (bp >= ep) // return pointer to start when it arrives at the end. TM: changed == to >=
1791  x->c_phase = 0;
1792  else
1793  x->c_phase = phase + blocksize;
1794 
1795  if (x->grainCounter < renderInterval)
1796  x->grainCounter++;
1797  break;
1798  ////////////////////////////////////////////////////////////////////////////////
1799 
1800  case Properties::X_FADE_LITE: // with crossfade between delay
1801 
1802  while (n--)
1803  {
1804  //Write to delay line
1805  double f = *in++; // get input
1806  *(bp) = f;
1807  *(bp + Properties::DELAYSIZE) = f;
1808 
1809  if (fades->isActive()) // we're crossfading!
1810  {
1811  for (int k = 0; k < numChannels; ++k)
1812  {
1813  oldSamp = newSamp = 0.0;
1814  *out[k] = 0.0;
1815  newReflSamps = 0.0;
1816  oldReflSamps= 0.0;
1817 
1818  if (micGainNonZero[k])
1819  {
1820  for (int reflNum = maxDynRefl - 1; reflNum >= Properties::DIRECT; --reflNum) // TM: if x->maxDynRefl is always same as x->numRefl, why is it necessary?
1821  {
1822  reflOrderIndex = reflNum + maxDynRefl * k;
1823 
1824  idelay = *(delay + reflOrderIndex) - 0.5; // a bit more efficient that the two lines above
1825  idelayOld = *(currentDelay + reflOrderIndex) - 0.5;
1826 
1827  switch (reflNum)
1828  {
1829  // direct sound
1830  case 0:
1831  oldSamp = *(currentSensitivity + reflOrderIndex) * *(bp + Properties::DELAYSIZE - idelayOld);
1832  newSamp = *(sensitivity + reflOrderIndex) * *(bp + Properties::DELAYSIZE - idelay);
1833  *out[k] += fades->tick(newSamp, oldSamp); // write cross fade of signals to output
1834  break;
1835 
1836  // 1st order reflections, filtered by walls and air absorption
1837  case 1:
1838  oldReflSamps += *(currentSensitivity + reflOrderIndex) * *(bp + Properties::DELAYSIZE - idelayOld);
1839  newReflSamps += *(sensitivity + reflOrderIndex) * *(bp + Properties::DELAYSIZE - idelay);
1840 
1841  *out[k] = xfadeWalls[k][0].tick(*out[k] + fades->tick(newReflSamps, oldReflSamps));
1842  *out[k] = xfadeAir[k].tick(*out[k]); // filter all by air filter
1843  break;
1844 
1845  // 2nd order reflections
1846  case 7:
1847  oldReflSamps += *(currentSensitivity + reflOrderIndex) * *(bp + Properties::DELAYSIZE - idelayOld);
1848  newReflSamps += *(sensitivity + reflOrderIndex) * *(bp + Properties::DELAYSIZE - idelay);
1849 
1850  *out[k] = xfadeWalls[k][1].tick(fades->tick(newReflSamps, oldReflSamps));
1851  newReflSamps = 0.0;
1852  oldReflSamps = 0.0;
1853  break;
1854 
1855  default:
1856  oldReflSamps += *(currentSensitivity + reflOrderIndex) * *(bp + Properties::DELAYSIZE - idelayOld);
1857  newReflSamps += *(sensitivity + reflOrderIndex) * *(bp + Properties::DELAYSIZE - idelay);
1858  break;
1859  }
1860  }
1861  }
1862  out[k]++;
1863  }
1864 
1865  fades->increment(); // update crossfade counters by one sample
1866  // TM: Don't take anything else out of this
1867  if (!fades->isActive()) // if done crossfading
1868  {
1869  for (int k = 0; k < numChannels; ++k)
1870  {
1871  numOfReflTimesK = numOfRefl * k;
1872  for (int reflNum = maxDynRefl - 1; reflNum >= Properties::DIRECT; --reflNum) // TM: if x->maxDynRefl is always same as x->numRefl, why is it necessary?
1873  {
1874  reflOrderIndex = reflNum + numOfReflTimesK;//maxDynRefl * k;
1875  *(currentDelay + reflOrderIndex) = *(delay + reflOrderIndex); // Update delays and sensitivities
1876  *(currentSensitivity + reflOrderIndex) = *(sensitivity + reflOrderIndex);
1877  }
1878  }
1879  }
1880 
1881  for (int reflNum = 0 ; reflNum < numChannels * numOfRefl ; ++reflNum) //NP: not sure if we need this for X-fade methods...
1882  { //We need to update the Sensi and Delay vector so that in case for a new bang, the correct grains can be calculated
1883  x->currentSensitivity[reflNum] = *(currentSensitivity + reflNum);
1884  x->currentDelay[reflNum] = *(currentDelay + reflNum);
1885  }
1886 
1887  }
1888  else // steady state, not crossfading
1889  {
1890  for (int k = 0; k < numChannels; ++k)
1891  {
1892  *out[k] = 0.0;
1893  reflSamps = 0.0;
1894  numOfReflTimesK = numOfRefl * k;
1895  if (micGainNonZero[k])
1896  {
1897  for (int reflNum = numOfRefl - 1; reflNum >= Properties::DIRECT; --reflNum) // iterate backward through reflections, to filter
1898  {
1899  reflOrderIndex = reflNum +numOfReflTimesK;
1900 
1901  // update sensitivity
1902  if (GrainCounter < renderInterval)
1903  *(currentSensitivity + reflOrderIndex) += *(sensiGrain + reflOrderIndex);
1904  else
1905  {
1906  *(currentDelay + reflOrderIndex) = *(delay + reflOrderIndex); // Update delay time
1907  *(currentSensitivity + reflOrderIndex) = *(sensitivity + reflOrderIndex);
1908  }
1909 
1910  idelay = *(currentDelay + reflOrderIndex) - 0.5;
1911 
1912  switch (reflNum)
1913  {
1914  case Properties::DIRECT:
1915  *out[k] = (*(currentSensitivity + reflOrderIndex) *
1916  *(bp + Properties::DELAYSIZE - idelay)) + reflSamps;
1917  break;
1918  // sample is filtered by first order reflection filter only and air
1919  case 1:
1920  reflSamps += (*(currentSensitivity + reflOrderIndex) *
1921  *(bp + Properties::DELAYSIZE - idelay));
1922 
1923  reflSamps = xfadeWalls[k][0].tick(reflSamps);
1924  reflSamps = xfadeAir[k].tick(reflSamps);
1925  break;
1926 
1927  case 7: // sample is filtered by 2nd order reflection filter only
1928  reflSamps += (*(currentSensitivity + reflOrderIndex) *
1929  *(bp + Properties::DELAYSIZE - idelay));
1930 
1931  reflSamps = xfadeWalls[k][1].tick(reflSamps);
1932  break;
1933 
1934  default:
1935  reflSamps += (*(currentSensitivity + reflOrderIndex) *
1936  *(bp + Properties::DELAYSIZE - idelay));
1937  break;
1938  }
1939  }
1940  }
1941  out[k]++;
1942  }
1943  }
1944  bp++;
1945  } // end of while
1946 
1947  if (bp >= ep) // return pointer to start when it arrives at the end. TM: changed == to >=
1948  x->c_phase = 0;
1949  else
1950  x->c_phase = phase + blocksize;
1951 
1952  if (x->grainCounter < renderInterval)
1953  x->grainCounter++;
1954 
1955  break;
1956 
1957  /********************************************************************************************************************************************************************/
1958  /********************************************************************************************************************************************************************/
1959  case Properties::X_FADE_XL: // with crossfade between delay, independent filtering for each wall
1960  double oldFilterInputSamp, newFilterInputSamp;
1961 
1962  while (n--)
1963  {
1964  //Write to delay line
1965  double f = *in++; // get input
1966  *(bp) = f;
1967  *(bp + Properties::DELAYSIZE) = f;
1968 
1969  if (fades->isActive()) // we're crossfading!
1970  {
1971  for (int k = 0; k < numChannels; ++k)
1972  {
1973  oldFilterInputSamp = newFilterInputSamp = 0.0;
1974  frontSamps = rearSamps = floorSamps = ceilSamps = reflSamps = 0.0;
1975  *out[k] = 0.0;
1976  numOfReflTimesK = numOfRefl * k;
1977 
1978  if (micGainNonZero[k])
1979  {
1980  for (int reflNum = maxDynRefl - 1; reflNum >= Properties::DIRECT; --reflNum)// TM: if x->maxDynRefl is always same as x->numRefl, why is it necessary?
1981  {
1982  reflOrderIndex = reflNum + numOfReflTimesK;
1983  idelay = *(delay + reflOrderIndex) - 0.5; // a bit more efficient that the two lines above
1984  idelayOld = *(currentDelay + reflOrderIndex) - 0.5;
1985 
1986  oldFilterInputSamp = *(currentSensitivity + reflOrderIndex) * *(bp + Properties::DELAYSIZE - idelayOld);
1987  newFilterInputSamp = *(sensitivity + reflOrderIndex) * *(bp + Properties::DELAYSIZE - idelay);
1988 
1989  switch (reflNum)
1990  {
1991  case Properties::FRONT_FLOOR:
1992  floorSamps += walls[k][Properties::FRONT + numwallsMinusOne].tick(fades->tick(newFilterInputSamp, oldFilterInputSamp));
1993  break;
1994  case Properties::REAR_FLOOR:
1995  floorSamps += walls[k][Properties::REAR + numwallsMinusOne].tick(fades->tick(newFilterInputSamp, oldFilterInputSamp));
1996  break;
1997  case Properties::LEFT_FLOOR:
1998  floorSamps += walls[k][Properties::LEFT + numwallsMinusOne].tick(fades->tick(newFilterInputSamp, oldFilterInputSamp));
1999  break;
2000  case Properties::RIGHT_FLOOR:
2001  floorSamps += walls[k][Properties::RIGHT + numwallsMinusOne].tick(fades->tick(newFilterInputSamp, oldFilterInputSamp));
2002  break;
2003 
2004  case Properties::LEFT_CEILING:
2005  ceilSamps += walls[k][Properties::LEFT + numwallsMinusOne].tick(fades->tick(newFilterInputSamp, oldFilterInputSamp));
2006  break;
2007  case Properties::RIGHT_CEILING:
2008  ceilSamps += walls[k][Properties::RIGHT + numwallsMinusOne].tick(fades->tick(newFilterInputSamp, oldFilterInputSamp));
2009  break;
2010  case Properties::FRONT_CEILING:
2011  ceilSamps += walls[k][Properties::FRONT + numwallsMinusOne].tick(fades->tick(newFilterInputSamp, oldFilterInputSamp));
2012  break;
2013  case Properties::REAR_CEILING:
2014  ceilSamps += walls[k][Properties::REAR + numwallsMinusOne].tick(fades->tick(newFilterInputSamp, oldFilterInputSamp));
2015  break;
2016 
2017  case Properties::LEFT_FRONT:
2018  frontSamps += walls[k][Properties::LEFT + numwallsMinusOne].tick(fades->tick(newFilterInputSamp, oldFilterInputSamp));
2019  break;
2020  case Properties::RIGHT_FRONT:
2021  frontSamps += walls[k][Properties::RIGHT + numwallsMinusOne].tick(fades->tick(newFilterInputSamp, oldFilterInputSamp));
2022  break;
2023 
2024  case Properties::LEFT_REAR:
2025  rearSamps += walls[k][Properties::LEFT + numwallsMinusOne].tick(fades->tick(newFilterInputSamp, oldFilterInputSamp));
2026  break;
2027  case Properties::RIGHT_REAR:
2028  rearSamps += walls[k][Properties::RIGHT + numwallsMinusOne].tick(fades->tick(newFilterInputSamp, oldFilterInputSamp));
2029  break;
2030 
2031  // direct sound
2032  case Properties::AIR:
2033  *out[k] +=fades->tick(newFilterInputSamp, oldFilterInputSamp);
2034  break;
2035 
2036  case Properties::LEFT:
2037  reflSamps = walls[k][Properties::LEFT - 1].tick(fades->tick(newFilterInputSamp, oldFilterInputSamp));
2038  *out[k] = walls[k][0].tick(reflSamps); // apply air filter at this last stage
2039  break;
2040 
2041  case Properties::RIGHT:
2042  reflSamps += walls[k][Properties::RIGHT - 1].tick(fades->tick(newFilterInputSamp, oldFilterInputSamp));
2043  break;
2044 
2045  case Properties::FRONT:
2046  frontSamps += fades->tick(newFilterInputSamp, oldFilterInputSamp);
2047  reflSamps += walls[k][Properties::FRONT - 1].tick(frontSamps);
2048  break;
2049 
2050  case Properties::REAR:
2051  rearSamps += fades->tick(newFilterInputSamp, oldFilterInputSamp);
2052  reflSamps += walls[k][Properties::REAR - 1].tick(rearSamps);
2053  break;
2054 
2055  case Properties::FLOOR:
2056  floorSamps += fades->tick(newFilterInputSamp, oldFilterInputSamp);
2057  reflSamps += walls[k][Properties::FLOOR - 1].tick(floorSamps);
2058  break;
2059 
2060  case Properties::CEILING:
2061  ceilSamps += fades->tick(newFilterInputSamp, oldFilterInputSamp);
2062  reflSamps += walls[k][Properties::CEILING - 1].tick(ceilSamps);
2063  break;
2064  }
2065  }
2066  }
2067  out[k]++;
2068  }
2069 
2070  fades->increment(); // update crossfade counters by one sample
2071 
2072  // TM: Don't take anything else out of this
2073  if (!fades->isActive()) // if done crossfading
2074  {
2075  for (int k = 0; k < numChannels; ++k)
2076  {
2077  numOfReflTimesK = numOfRefl * k;
2078  for (int reflNum = maxDynRefl - 1; reflNum >= Properties::DIRECT; --reflNum) // TM: if x->maxDynRefl is always same as x->numRefl, why is it necessary?
2079  {
2080  reflOrderIndex = reflNum + numOfReflTimesK;//maxDynRefl * k;
2081  *(currentDelay + reflOrderIndex) = *(delay + reflOrderIndex); // Update delays and sensitivities
2082  *(currentSensitivity + reflOrderIndex) = *(sensitivity + reflOrderIndex);
2083 
2084  }
2085  }
2086  }
2087 
2088  for (int reflNum = 0 ; reflNum < numChannels * numOfRefl ; ++reflNum) //NP: not sure if we need this for X-fade methods...
2089  { //We need to update the Sensi and Delay vector so that in case for a new bang, the correct grains can be calculated
2090  x->currentSensitivity[reflNum] = *(currentSensitivity + reflNum);
2091  x->currentDelay[reflNum] = *(currentDelay + reflNum);
2092  }
2093  }
2094  else // steady state, not crossfading
2095  {
2096  for (int k = 0; k < numChannels; ++k)
2097  {
2098  *out[k] = 0.0;
2099  reflSamps = 0.0;
2100  frontSamps = rearSamps = floorSamps = ceilSamps = reflSamps = filterInputSamp = 0.0;
2101  numOfReflTimesK = numOfRefl * k;
2102  if (micGainNonZero[k])
2103  {
2104  for (int reflNum = numOfRefl - 1; reflNum >= Properties::DIRECT; --reflNum) // iterate backward through reflections, to filter
2105  {
2106  reflOrderIndex = reflNum + numOfReflTimesK;
2107 
2108  // update sensitivity
2109  if (GrainCounter < renderInterval)
2110  *(currentSensitivity + reflOrderIndex) += *(sensiGrain + reflOrderIndex);
2111  else
2112  {
2113  *(currentSensitivity + reflOrderIndex) = *(sensitivity + reflOrderIndex);
2114  *(currentDelay + reflOrderIndex) = *(delay + reflOrderIndex); // Update delay time
2115  }
2116 
2117  idelay = *(currentDelay + reflOrderIndex) - 0.5;
2118  filterInputSamp = *(currentSensitivity + reflOrderIndex) * *(bp + Properties::DELAYSIZE - idelay);
2119 
2120  switch (reflNum) // TODO: is there a cleaner but also clear way of doing this that is as fast?
2121  {
2122  case Properties::FRONT_FLOOR:
2123  floorSamps += walls[k][Properties::FRONT + numwallsMinusOne].tick(filterInputSamp);
2124  break;
2125  case Properties::REAR_FLOOR:
2126  floorSamps += walls[k][Properties::REAR + numwallsMinusOne].tick(filterInputSamp);
2127  break;
2128  case Properties::LEFT_FLOOR:
2129  floorSamps += walls[k][Properties::LEFT + numwallsMinusOne].tick(filterInputSamp);
2130  break;
2131  case Properties::RIGHT_FLOOR:
2132  floorSamps += walls[k][Properties::RIGHT + numwallsMinusOne].tick(filterInputSamp);
2133  break;
2134 
2135  case Properties::LEFT_CEILING:
2136  ceilSamps += walls[k][Properties::LEFT + numwallsMinusOne].tick(filterInputSamp);
2137  break;
2138  case Properties::RIGHT_CEILING:
2139  ceilSamps += walls[k][Properties::RIGHT + numwallsMinusOne].tick(filterInputSamp);
2140  break;
2141  case Properties::FRONT_CEILING:
2142  ceilSamps += walls[k][Properties::FRONT + numwallsMinusOne].tick(filterInputSamp);
2143  break;
2144  case Properties::REAR_CEILING:
2145  ceilSamps += walls[k][Properties::REAR + numwallsMinusOne].tick(filterInputSamp);
2146  break;
2147 
2148  case Properties::LEFT_FRONT:
2149  frontSamps += walls[k][Properties::LEFT + numwallsMinusOne].tick(filterInputSamp);
2150  break;
2151  case Properties::RIGHT_FRONT:
2152  frontSamps += walls[k][Properties::RIGHT + numwallsMinusOne].tick(filterInputSamp);
2153  break;
2154 
2155  case Properties::LEFT_REAR:
2156  rearSamps += walls[k][Properties::LEFT + numwallsMinusOne].tick(filterInputSamp);
2157  break;
2158  case Properties::RIGHT_REAR:
2159  rearSamps += walls[k][Properties::RIGHT + numwallsMinusOne].tick(filterInputSamp);
2160  break;
2161 
2162  case Properties::DIRECT: // filtered direct sound
2163  *out[k] += filterInputSamp;
2164  break;
2165 
2166  // after one reflection
2167  case Properties::LEFT:
2168  reflSamps += walls[k][Properties::LEFT - 1].tick(filterInputSamp); // sum first order reflections
2169  *out[k] = air[k][0].tick(reflSamps);
2170  break;
2171 
2172  case Properties::RIGHT:
2173  reflSamps += walls[k][Properties::RIGHT - 1].tick(filterInputSamp); // sum first order reflections
2174  break;
2175 
2176  case Properties::FRONT:
2177  frontSamps += filterInputSamp;
2178  reflSamps += walls[k][Properties::FRONT - 1].tick(frontSamps); // write reflections to output
2179  break;
2180 
2181  case Properties::REAR:
2182  rearSamps += filterInputSamp;
2183  reflSamps += walls[k][Properties::REAR - 1].tick(rearSamps); // write reflections to output
2184  break;
2185 
2186  case Properties::FLOOR:
2187  floorSamps += filterInputSamp;
2188  reflSamps += walls[k][Properties::FLOOR - 1].tick(floorSamps); // write reflections to output
2189  break;
2190 
2191  case Properties::CEILING:
2192  ceilSamps += filterInputSamp;
2193  reflSamps += walls[k][Properties::CEILING - 1].tick(ceilSamps); // write first order reflection to output
2194  break;
2195  }
2196  }
2197  }
2198  out[k]++;
2199  }
2200  }
2201  bp++;
2202  } // end of while
2203 
2204  if (bp >= ep) // return pointer to start when it arrives at the end. TM: changed == to >=
2205  x->c_phase = 0;
2206  else
2207  x->c_phase = phase + blocksize;
2208  if (x->grainCounter < renderInterval)
2209  x->grainCounter++;
2210  break;
2211 
2212  /* END OF X_FADE_XL */
2213  /********************************************************************************************************************************************************************/
2214  /********************************************************************************************************************************************************************/
2215 
2216  case Properties::AMP_PAN: // amplitude panning only
2217  if (GrainCounter < renderInterval)
2218  {
2219  while (n--)
2220  {
2221  //Write to delay line
2222  double f = *in++; // get input
2223  *(bp) = f;
2224  *(bp + Properties::DELAYSIZE) = f;
2225 
2226  for (int k = 0; k < numChannels; ++k)
2227  {
2228  *out[k] = 0.0;
2229  if (micGainNonZero[k])
2230  {
2231  reflOrderIndex = numOfRefl * k;
2232  *(currentSensitivity + reflOrderIndex) += *(sensiGrain + reflOrderIndex);
2233  *out[k] = (*(currentSensitivity + reflOrderIndex) * f);
2234  }
2235  out[k]++;
2236  }
2237  bp++;
2238  } // end of while
2239  for (int reflNum = 0 ; reflNum < numChannels * numOfRefl ; ++reflNum) //NP: not sure if we need this for X-fade methods...
2240  { //We need to update the Sensi and Delay vector so that in case for a new bang, the correct grains can be calculated
2241  x->currentSensitivity[reflNum] = *(currentSensitivity + reflNum);
2242  }
2243 
2244  }
2245  else
2246  {
2247  while (n--)
2248  {
2249  //Write to delay line
2250  double f = *in++; // get input
2251  *(bp) = f;
2252  *(bp + Properties::DELAYSIZE) = f;
2253 
2254  for (int k = 0; k < numChannels; ++k)
2255  {
2256  if (micGainNonZero[k])// && reflGains[0] != 0.0)
2257  *out[k] = (*(currentSensitivity + numOfRefl * k) * f);
2258  else
2259  *out[k] = 0.0;
2260  out[k]++;
2261  }
2262  bp++;
2263  } // end of while
2264  }
2265  if (x->grainCounter < renderInterval)
2266  x->grainCounter++;
2267  break;
2268  ////////////////////////////////////////////////////////////////////////////////
2269  case Properties::STATIC: // Nothing moves, only integer delays
2270  if (GrainCounter < renderInterval)
2271  {
2272  while (n--)
2273  {
2274  //Write to delay line
2275  double f = *in++; // get input
2276  *(bp) = f;
2277  *(bp + Properties::DELAYSIZE) = f;
2278 
2279  for (int k = 0; k < numChannels; ++k)
2280  {
2281  *out[k] = 0.0;
2282  reflSamps = 0.0;
2283  numOfReflTimesK = numOfRefl * k;
2284 
2285  if (micGainNonZero[k])
2286  {
2287  for (int reflNum = numOfRefl - 1; reflNum >= Properties::DIRECT; --reflNum)
2288  {
2289  reflOrderIndex = reflNum + numOfReflTimesK;
2290  *(currentDelay + reflOrderIndex) += *(delGrain + reflOrderIndex); // TM: Changed
2291  *(currentSensitivity + reflOrderIndex) += *(sensiGrain + reflOrderIndex);
2292  idelay = *(currentDelay + reflOrderIndex) - 0.5;
2293 
2294  switch (reflNum)
2295  {
2296  case 0:
2297  *out[k] = *(currentSensitivity + reflOrderIndex) * *(bp + Properties::DELAYSIZE - idelay) + reflSamps;
2298  break;
2299 
2300  case 1:
2301  reflSamps += *(currentSensitivity + reflOrderIndex) * *(bp + Properties::DELAYSIZE - idelay);
2302  reflSamps = air[k][0].tick(walls[k][0].tick(reflSamps));
2303  break;
2304 
2305  case 7:
2306  reflSamps += *(currentSensitivity + reflOrderIndex) * *(bp + Properties::DELAYSIZE - idelay);
2307  reflSamps = walls[k][6].tick(reflSamps);
2308  break;
2309 
2310  default:
2311  reflSamps += *(currentSensitivity + reflOrderIndex) * *(bp + Properties::DELAYSIZE - idelay);
2312  break;
2313  }
2314  }
2315  }
2316  out[k]++;
2317  }
2318  bp++;
2319  } // end of while
2320 
2321  for (int reflNum = 0 ; reflNum < numChannels * numOfRefl ; ++reflNum)
2322  { //We need to update the Sensi and Delay vector so that in case for a new bang, the correct grains can be calculated
2323  x->currentSensitivity[reflNum] = *(currentSensitivity + reflNum);
2324  x->currentDelay[reflNum] = *(currentDelay + reflNum);
2325  }
2326 
2327  }
2328  else // steady state
2329  {
2330  while (n--)
2331  {
2332  //Write to delay line
2333  double f = *in++; // get input
2334  *(bp) = f;
2335  *(bp + Properties::DELAYSIZE) = f;
2336 
2337  for (int k=0; k < numChannels; ++k)
2338  {
2339  *out[k] = 0.0;
2340  reflSamps = 0.0;
2341  numOfReflTimesK = numOfRefl * k;
2342 
2343  if (micGainNonZero[k])
2344  {
2345  for (int reflNum = numOfRefl - 1; reflNum >= Properties::DIRECT; --reflNum)
2346  {
2347  reflOrderIndex = reflNum + numOfReflTimesK;
2348  idelay = *(currentDelay + reflOrderIndex) - 0.5;
2349 
2350  switch (reflNum)
2351  {
2352  case 0:
2353  *out[k] = *(currentSensitivity + reflOrderIndex) * *(bp + Properties::DELAYSIZE - idelay) + reflSamps;
2354  break;
2355 
2356  case 1:
2357  reflSamps += *(currentSensitivity + reflOrderIndex) * *(bp + Properties::DELAYSIZE - idelay);
2358  reflSamps = air[k][0].tick(walls[k][0].tick(reflSamps));
2359  break;
2360 
2361  case 7:
2362  reflSamps += *(currentSensitivity + reflOrderIndex) * *(bp + Properties::DELAYSIZE - idelay);
2363  reflSamps = walls[k][6].tick(reflSamps);
2364  break;
2365 
2366  default:
2367  reflSamps += *(currentSensitivity + reflOrderIndex) * *(bp + Properties::DELAYSIZE - idelay);
2368  break;
2369  }
2370  }
2371  }
2372  out[k]++;
2373  }
2374  bp++;
2375  } // end of while
2376  }
2377  if (bp >= ep) // return pointer to start when it arrives at the end. TM: changed == to >=
2378  x->c_phase = 0;
2379  else
2380  x->c_phase = phase + blocksize;
2381  if (x->grainCounter < renderInterval)
2382  x->grainCounter++;
2383  break;
2384  /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2385  case Properties::NONE: // no audio
2386  while (n--)
2387  {
2388  //Write to delay line so that the internal buffer doesn't contain crap if the rendermode changes
2389  double f = *in++; // get input
2390  *(bp) = f;
2391  *(bp + Properties::DELAYSIZE) = f;
2392 
2393  for (int k = 0; k < numChannels; ++k)
2394  *out[k]++ = 0.0;
2395  bp++;
2396  }
2397  if (bp >= ep) // return pointer to start when it arrives at the end. TM: changed == to >=
2398  x->c_phase = 0;
2399  else
2400  x->c_phase = phase + blocksize;
2401  if (x->grainCounter < renderInterval)
2402  x->grainCounter++;
2403  break;
2404  }
2405  return (w + 4 + numChannels);
2406 }
2407 
2408 #pragma warning(pop)
2409 
2410 void vimic_dsp(t_vimic *x, t_signal **sp, short *count)
2411 {
2412  // clear out the delay line
2413  for (int n = 0; n < Properties::DELAYBYTES; n++)
2414  x->c_vec[n] = 0.0;
2415 
2416  if (x->x_sr != (double)sp[0]->s_sr)
2417  {
2418  x->x_sr = (double) sp[0]->s_sr;
2419  x->speedOfSound = (331.3 * sqrt(1.0 + x->temperature / 273.15)) / x->x_sr;
2420  x->invSpeedOfSound = 1.0 / x->speedOfSound;
2421  }
2422 
2423  // sp[0]->s_n is the vector size
2424  if (x->blocksize != (int)sp[0]->s_n)
2425  {
2426  x->blocksize = (int)sp[0]->s_n;
2427  //post("Grainsize was %f", x->grainsize);
2428  x->grainsize = 1.0 / (x->blocksize * x->renderInterval);
2429  //post("Grainsize is now %f", x->grainsize);
2430  //post("blocksize is now %d", (int)sp[0]->s_n);
2431  }
2432 
2433  short num_args = x->numOfChannels + 3;
2434 
2435  if (num_args < 4 || num_args > 147)
2436  post( "j.vimic~ : Combination of Reflection Order and Channels not supported" );
2437 
2438  t_int **vec = (t_int **) getbytes(sizeof(t_int *) * num_args); // vector of pointers
2439 
2440  vec[0] = (t_int *)x; // first arg is x struct pointer
2441  int i;
2442  for (i = 0; i < num_args - 2; i++)
2443  vec[i + 1] = (t_int *) sp[i]->s_vec;
2444 
2445  vec[i + 1] = (t_int *) sp[0]->s_n; // last arg = sp[0]->s_n is signal vector size
2446 
2447  dsp_addv(vimic_perform, num_args, (void **)vec);
2448 
2449  freebytes(vec, sizeof(t_int *) * num_args); // deallocate vector of pointers
2450 }
2451 
2452 void vimic_assist(t_vimic *x, Object *b, long msg, long arg, char *s)
2453 {
2454  // copy the appropriate message to the destination string
2455  if (msg == ASSIST_INLET)
2456  {
2457  switch (arg)
2458  {
2459  case 0:
2460  snprintf(s, 256, "%s", "Bang, anything, direct sound");
2461  break;
2462  /*case 1:
2463  sprintf(s, "%s", "1st order refl.");
2464  break;
2465  case 2:
2466  sprintf(s, "%s", "2nd order refl.");
2467  break;
2468  case 3:
2469  sprintf(s, "%s", "3rd order refl.");
2470  break; */
2471  }
2472  }
2473  else if (msg == ASSIST_OUTLET)
2474  snprintf(s, 256, "%s %ld", "Output", arg + 1);
2475 }
2476 
2477 void vimic_perform64(t_vimic *x, t_object *dsp64, double **ins, long numins, double **outs, long numouts, long sampleframes, long flags, void *userparam)
2478 {
2479  int numChannels = x->numOfChannels;
2480  bool micGainNonZero[Properties::MAXNUMCHANNELS];
2481 
2482  int phase = x->c_phase;
2483  int renderInterval = x->renderInterval;
2484  int GrainCounter = x->grainCounter;
2485  int numOfRefl = x->numRefl;
2486  int maxDynRefl = x->maxDynRefl;
2487  int reflOrderIndex = 0;
2488 
2489  double *reflGains = x->reflGains;
2490  double *currentDelay = x->currentDelay;
2491  double *currentSensitivity = x->currentSensitivity;
2492  double *delGrain = x->delGrain;
2493  double *sensiGrain = x->sensiGrain;
2494  double *bp = x->c_vec + phase;
2495  double *ep = x->c_vec + Properties::DELAYSIZE;
2496  double *delay = x->delay;
2497  double *sensitivity = x->sensitivity;
2498 
2499  double frac;
2500  int idelay, idelayOld;
2501  double newSamp, oldSamp, newReflSamps, oldReflSamps, reflSamps = 0.0;
2502 
2503  int sampPos = 0;
2504 
2505  int numwallsMinusOne = Properties::NUMWALLS - 1; //optimization
2506  int numOfReflTimesK;
2507 
2508  HiMidLow **walls = x->room->walls;
2509  LowPass **air = x->room->air;
2510 
2511  // for Xfade
2512  HiMidLow **xfadeWalls = x->room->xfadeWalls;
2513  LowPass *xfadeAir = x->room->xfadeAir;
2514  CrossFadeQueue *fades = x->fades;
2515 
2516  // variables for fractional delay lines
2517  double a, b, c, d, cminusb;
2518 
2519  for (int i = 0; i < numChannels; ++i)
2520  {
2521  if (x->room->mics[i].gain() != 0.0)
2522  micGainNonZero[i] = true;
2523  else
2524  micGainNonZero[i] = false;
2525  }
2526 
2527  //copying input to delayline
2528  memcpy(bp, ins[0], sizeof(double) * sampleframes);
2529  memcpy((bp + Properties::DELAYSIZE), ins[0], sizeof(double) * sampleframes);
2530 
2531  switch (x->AudioProcType)
2532  {
2533  case Properties::VIMIC_LITE: // ViMiC wtih reduced Filtering
2534 
2535  if (GrainCounter < renderInterval) {
2536  for (int k = 0; k < numChannels; ++k) {
2537  memset(outs[k], 0, sizeof(double) * sampleframes);
2538  numOfReflTimesK = numOfRefl * k;
2539  if (micGainNonZero[k]) {
2540  for (int n=0 ; n < sampleframes; n++) {
2541  reflSamps = 0.0;
2542  // TM: if x->maxDynRefl is always same as x->numRefl, why is it necessary?
2543  for (int reflNum = maxDynRefl - 1; reflNum >= Properties::DIRECT; --reflNum) {
2544  reflOrderIndex = reflNum + numOfReflTimesK;
2545  *(currentDelay + reflOrderIndex) += *(delGrain + reflOrderIndex); // TM: Changed
2546  *(currentSensitivity + reflOrderIndex) += *(sensiGrain + reflOrderIndex);
2547  if (*(currentSensitivity + reflOrderIndex) != 0.0) {
2548  idelay = *(currentDelay + reflOrderIndex) + 0.5;
2549  frac = *(currentDelay + reflOrderIndex) - (double) idelay; // fractional part of delay value
2550  sampPos = Properties::DELAYSIZE - idelay + n;
2551 
2552  d = *(bp + sampPos - 3);
2553  c = *(bp + sampPos - 2);
2554  b = *(bp + sampPos - 1);
2555  a = *(bp + sampPos);
2556  cminusb = c - b;
2557 
2558  switch (reflNum) {
2559  case 0: // sum direct sound with reflections
2560  outs[k][n] = (*(currentSensitivity + reflOrderIndex) * (b + frac * (cminusb - 0.1666667 * (1.0 - frac)
2561  * ((d - a - 3.0 * cminusb) * frac + (d + 2.0 * a - 3.0 * b))))) + reflSamps;
2562  break;
2563  case 1: // sum 1st order reflections (potentially with 2nd order reflections)
2564  reflSamps += *(currentSensitivity + reflOrderIndex)
2565  * (b + frac * (cminusb - 0.1666667 * (1.0 - frac) * ((d - a - 3.0 * cminusb)
2566  * frac + (d + 2.0 * a - 3.0 * b))));
2567  reflSamps = air[k][0].tick(walls[k][0].tick(reflSamps));
2568  break;
2569  case 7: // sum 2nd order reflections
2570  reflSamps += *(currentSensitivity + reflOrderIndex)
2571  * (b + frac * (cminusb - 0.1666667 * (1.0 - frac) * ((d - a - 3.0 * cminusb)
2572  * frac + (d + 2.0 * a - 3.0 * b))));
2573  reflSamps = walls[k][6].tick(reflSamps);
2574  break;
2575  default:
2576  reflSamps += *(currentSensitivity + reflOrderIndex)
2577  * (b + frac * (cminusb - 0.1666667 * (1.0 - frac) * ((d - a - 3.0 * cminusb)
2578  * frac + (d + 2.0 * a - 3.0 * b))));
2579  break;
2580  }
2581  }
2582  else {
2583  switch (reflNum) {
2584  case 1: // sum 1st order reflections (potentially with 2nd order reflections)
2585  reflSamps = air[k][0].tick(walls[k][0].tick(reflSamps));
2586  break;
2587  case 7: // sum 2nd order reflections
2588  reflSamps = walls[k][6].tick(reflSamps);
2589  break;
2590  }
2591  }
2592  }
2593  }
2594  }
2595  }
2596  bp += sampleframes;
2597  for (int reflNum = 0 ; reflNum < numChannels * numOfRefl ; ++reflNum) {
2598  //We need to update the Sensi and Delay vector so that in case for a new bang, the correct grains can be calculated
2599  x->currentSensitivity[reflNum] = *(currentSensitivity + reflNum);
2600  x->currentDelay[reflNum] = *(currentDelay + reflNum);
2601  }
2602  }
2603  else { // steady state, non-fractional delay, constant values
2604  for (int k = 0; k < numChannels; ++k) {
2605  memset(outs[k], 0, sizeof(double) * sampleframes);
2606  numOfReflTimesK = numOfRefl * k;
2607  if (micGainNonZero[k]) {
2608  for (int n=0 ; n < sampleframes; n++) {
2609  reflSamps = 0.0;
2610  sampPos = n + Properties::DELAYSIZE;
2611  for (int reflNum = numOfRefl - 1; reflNum >= Properties::DIRECT; --reflNum) {
2612  reflOrderIndex = reflNum + numOfReflTimesK;
2613  idelay = *(currentDelay + reflOrderIndex) +1.5; //was - 0.5; but I think that we cause a general delay of 2 samples due to the interpolation, so we have to respect that in the static method too, otherwise we will have small jumps of 2 samples back & forth
2614 
2615  switch (reflNum) {
2616  case 0:
2617  outs[k][n] = *(currentSensitivity + reflOrderIndex) * *(bp+ sampPos - idelay) + reflSamps;
2618  break;
2619 
2620  case 1:
2621  reflSamps += *(currentSensitivity + reflOrderIndex) * *(bp+sampPos - idelay);
2622  reflSamps = air[k][0].tick(walls[k][0].tick(reflSamps));
2623  break;
2624 
2625  case 7:
2626  reflSamps += *(currentSensitivity + reflOrderIndex) * *(bp+sampPos - idelay);
2627  reflSamps = walls[k][6].tick(reflSamps);
2628  break;
2629 
2630  default:
2631  reflSamps += *(currentSensitivity + reflOrderIndex) * *(bp+sampPos - idelay);
2632  break;
2633  }
2634  }
2635  }
2636  }
2637  }
2638  bp += sampleframes;
2639  }
2640 
2641  if (bp >= ep) // return pointer to start when it arrives at the end. TM: changed == to >=
2642  x->c_phase = 0;
2643  else
2644  x->c_phase = phase + sampleframes;
2645 
2646  if (x->grainCounter < renderInterval)
2647  x->grainCounter++;
2648  break;
2649  ////////////////////////////////////////////////////////////////////////////////
2650  case Properties::VIMIC_XL: // reflections are filtered
2651  double frontSamps, rearSamps, floorSamps, ceilSamps, filterInputSamp;
2652  if (GrainCounter < renderInterval) { // transitional state with fractional delay and interpolated values
2653  for (int k = 0; k < numChannels; ++k) {
2654  memset(outs[k],0 , sizeof(double)*sampleframes);
2655  if (micGainNonZero[k]) {
2656  numOfReflTimesK = numOfRefl * k;
2657  for (int n=0 ; n < sampleframes; n++) {
2658  frontSamps = rearSamps = floorSamps = ceilSamps = reflSamps = filterInputSamp = 0.0;
2659  for (int reflNum = maxDynRefl - 1; reflNum >= 0; --reflNum) { // TM: if x->maxDynRefl is always same as x->numRefl, why is it necessary?
2660  reflOrderIndex = reflNum + numOfReflTimesK;
2661  *(currentDelay + reflOrderIndex) += *(delGrain + reflOrderIndex); // TM: Changed
2662  *(currentSensitivity + reflOrderIndex) += *(sensiGrain + reflOrderIndex);
2663 
2664  if (*(sensitivity + reflOrderIndex) != 0.0) {
2665  idelay = 0.5 + *(currentDelay + reflOrderIndex);
2666  frac = *(currentDelay + reflOrderIndex) - (double) idelay; // fractional part of delay value
2667  sampPos = Properties::DELAYSIZE - idelay + n;
2668 
2669  d = *(bp + sampPos - 3);
2670  c = *(bp + sampPos - 2);
2671  b = *(bp + sampPos - 1);
2672  a = *(bp + sampPos);
2673  cminusb = c - b;
2674 
2675  filterInputSamp = *(currentSensitivity + reflOrderIndex)
2676  * (b + frac * (cminusb - 0.1666667 * (1.0 - frac) * ((d - a - 3.0 * cminusb) * frac + (d + 2.0 * a - 3.0 * b))));
2677 
2678  switch (reflNum) // TODO: is there a cleaner and clear way of doing this that is as fast?
2679  {
2680  case Properties::FRONT_FLOOR:
2681  floorSamps += walls[k][Properties::FRONT + numwallsMinusOne].tick(filterInputSamp);
2682  break;
2683  case Properties::REAR_FLOOR:
2684  floorSamps += walls[k][Properties::REAR + numwallsMinusOne].tick(filterInputSamp);
2685  break;
2686  case Properties::LEFT_FLOOR:
2687  floorSamps += walls[k][Properties::LEFT + numwallsMinusOne].tick(filterInputSamp);
2688  break;
2689  case Properties::RIGHT_FLOOR:
2690  floorSamps += walls[k][Properties::RIGHT + numwallsMinusOne].tick(filterInputSamp);
2691  break;
2692 
2693  case Properties::LEFT_CEILING:
2694  ceilSamps += walls[k][Properties::LEFT + numwallsMinusOne].tick(filterInputSamp);
2695  break;
2696  case Properties::RIGHT_CEILING:
2697  ceilSamps += walls[k][Properties::RIGHT + numwallsMinusOne].tick(filterInputSamp);
2698  break;
2699  case Properties::FRONT_CEILING:
2700  ceilSamps += walls[k][Properties::FRONT + numwallsMinusOne].tick(filterInputSamp);
2701  break;
2702  case Properties::REAR_CEILING:
2703  ceilSamps += walls[k][Properties::REAR + numwallsMinusOne].tick(filterInputSamp);
2704  break;
2705 
2706  case Properties::LEFT_FRONT:
2707  frontSamps += walls[k][Properties::LEFT + numwallsMinusOne].tick(filterInputSamp);
2708  break;
2709  case Properties::RIGHT_FRONT:
2710  frontSamps += walls[k][Properties::RIGHT + numwallsMinusOne].tick(filterInputSamp);
2711  break;
2712 
2713  case Properties::LEFT_REAR:
2714  rearSamps += walls[k][Properties::LEFT + numwallsMinusOne].tick(filterInputSamp);
2715  break;
2716  case Properties::RIGHT_REAR:
2717  rearSamps += walls[k][Properties::RIGHT + numwallsMinusOne].tick(filterInputSamp);
2718  break;
2719 
2720  case Properties::AIR:
2721  outs[k][n] += filterInputSamp;
2722  break;
2723 
2724  //after one reflection
2725 
2726  case Properties::LEFT:// after one reflection
2727  reflSamps += walls[k][0].tick(filterInputSamp); // write first order reflection to output [Properties::LEFT - 1]
2728  outs[k][n] = air[k][0].tick(reflSamps); // reflections are filtered by air absorption LPF
2729  break;
2730 
2731  case Properties::RIGHT:
2732  reflSamps += walls[k][1].tick(filterInputSamp); // write first order reflection to output [Properties::RIGHT - 1]
2733  break;
2734 
2735 
2736  case Properties::FRONT:
2737  frontSamps += filterInputSamp;
2738  reflSamps += walls[k][2].tick(frontSamps); // write reflections to output [Properties::FRONT - 1]
2739  break;
2740 
2741  case Properties::REAR:
2742  rearSamps += filterInputSamp;
2743  reflSamps += walls[k][3].tick(rearSamps); // write reflections to output [Properties::REAR - 1]
2744  break;
2745 
2746  case Properties::FLOOR:
2747  floorSamps += filterInputSamp;
2748  reflSamps += walls[k][4].tick(floorSamps); // write reflections to output [FLOOR - 1]
2749  break;
2750 
2751  case Properties::CEILING:
2752  ceilSamps += filterInputSamp;
2753  reflSamps += walls[k][5].tick(ceilSamps); // write first order reflection to output [CEILING - 1]
2754  break;
2755  }
2756  }
2757  else
2758  {
2759  switch (reflNum) { // TODO: is there a cleaner and clear way of doing this that is as fast?
2760  case Properties::FRONT_FLOOR:
2761  floorSamps += walls[k][Properties::FRONT + numwallsMinusOne].tick(filterInputSamp);
2762  break;
2763  case Properties::REAR_FLOOR:
2764  floorSamps += walls[k][Properties::REAR + numwallsMinusOne].tick(filterInputSamp);
2765  break;
2766  case Properties::LEFT_FLOOR:
2767  floorSamps += walls[k][Properties::LEFT + numwallsMinusOne].tick(filterInputSamp);
2768  break;
2769  case Properties::RIGHT_FLOOR:
2770  floorSamps += walls[k][Properties::RIGHT + numwallsMinusOne].tick(filterInputSamp);
2771  break;
2772  case Properties::LEFT_CEILING:
2773  ceilSamps += walls[k][Properties::LEFT + numwallsMinusOne].tick(filterInputSamp);
2774  break;
2775  case Properties::RIGHT_CEILING:
2776  ceilSamps += walls[k][Properties::RIGHT + numwallsMinusOne].tick(filterInputSamp);
2777  break;
2778  case Properties::FRONT_CEILING:
2779  ceilSamps += walls[k][Properties::FRONT + numwallsMinusOne].tick(filterInputSamp);
2780  break;
2781  case Properties::REAR_CEILING:
2782  ceilSamps += walls[k][Properties::REAR + numwallsMinusOne].tick(filterInputSamp);
2783  break;
2784 
2785  case Properties::LEFT_FRONT:
2786  frontSamps += walls[k][Properties::LEFT + numwallsMinusOne].tick(filterInputSamp);
2787  break;
2788  case Properties::RIGHT_FRONT:
2789  frontSamps += walls[k][Properties::RIGHT + numwallsMinusOne].tick(filterInputSamp);
2790  break;
2791 
2792  case Properties::LEFT_REAR:
2793  rearSamps += walls[k][Properties::LEFT + numwallsMinusOne].tick(filterInputSamp);
2794  break;
2795  case Properties::RIGHT_REAR:
2796  rearSamps += walls[k][Properties::RIGHT + numwallsMinusOne].tick(filterInputSamp);
2797  break;
2798 
2799  /*case AIR:
2800  *out[k] += filterInputSamp;
2801  break;*/
2802 
2803  //after one reflection
2804 
2805  case Properties::LEFT:// after one reflection
2806  reflSamps += walls[k][0].tick(filterInputSamp); // write first order reflection to output [Properties::LEFT - 1]
2807  outs[k][n] += air[k][0].tick(reflSamps); // reflections are filtered by air absorption LPF
2808  break;
2809  case Properties::RIGHT:
2810  reflSamps += walls[k][1].tick(filterInputSamp); // write first order reflection to output [Properties::RIGHT - 1]
2811  break;
2812 
2813 
2814  case Properties::FRONT:
2815  //frontSamps += filterInputSamp;
2816  reflSamps += walls[k][2].tick(frontSamps); // write reflections to output [Properties::FRONT - 1]
2817  break;
2818 
2819  case Properties::REAR:
2820  //rearSamps += filterInputSamp;
2821  reflSamps += walls[k][3].tick(rearSamps); // write reflections to output [Properties::REAR - 1]
2822  break;
2823 
2824  case Properties::FLOOR:
2825  //floorSamps += filterInputSamp;
2826  reflSamps += walls[k][4].tick(floorSamps); // write reflections to output [FLOOR - 1]
2827  break;
2828 
2829  case Properties::CEILING:
2830  //ceilSamps += filterInputSamp;
2831  reflSamps += walls[k][5].tick(ceilSamps); // write first order reflection to output [CEILING - 1]
2832  break;
2833  }
2834  }
2835  }
2836  }
2837  }
2838  }
2839  for (int reflNum = 0 ; reflNum < numChannels * numOfRefl ; ++reflNum) {
2840  //We need to update the Sensi and Delay vector so that in case for a new bang, the correct grains can be calculated
2841  x->currentSensitivity[reflNum] = *(currentSensitivity + reflNum);
2842  x->currentDelay[reflNum] = *(currentDelay + reflNum);
2843  }
2844  }
2845  else // steady state, non-fractional delay, constant values
2846  {
2847  for (int k = 0; k < numChannels; ++k) {
2848  memset(outs[k], 0, sizeof(double)*sampleframes);
2849  if (micGainNonZero[k]) {
2850  numOfReflTimesK = numOfRefl * k;
2851  for (int n=0 ; n < sampleframes; n++) {
2852  frontSamps = rearSamps = floorSamps = ceilSamps = reflSamps = filterInputSamp = 0.0;
2853  for (int reflNum = numOfRefl - 1; reflNum >= 0; --reflNum)
2854  {
2855  if (reflGains[0] != 0.0 || reflGains[1] != 0.0 || reflGains[2] != 0.0) // 0 for direct, 1 for 1st order, 2 for snd order
2856  {
2857  reflOrderIndex = reflNum + numOfReflTimesK;
2858  idelay = *(currentDelay + reflOrderIndex) +0.5;
2859  filterInputSamp = *(currentSensitivity + reflOrderIndex) * *(bp + Properties::DELAYSIZE - idelay + n);
2860 
2861  switch (reflNum) // TODO: is there a cleaner but also clear way of doing this that is as fast?
2862  {
2863  case Properties::FRONT_FLOOR:
2864  floorSamps += walls[k][Properties::FRONT + numwallsMinusOne].tick(filterInputSamp);
2865  break;
2866  case Properties::REAR_FLOOR:
2867  floorSamps += walls[k][Properties::REAR + numwallsMinusOne].tick(filterInputSamp);
2868  break;
2869  case Properties::LEFT_FLOOR:
2870  floorSamps += walls[k][Properties::LEFT + numwallsMinusOne].tick(filterInputSamp);
2871  break;
2872  case Properties::RIGHT_FLOOR:
2873  floorSamps += walls[k][Properties::RIGHT + numwallsMinusOne].tick(filterInputSamp);
2874  break;
2875  case Properties::LEFT_CEILING:
2876  ceilSamps += walls[k][Properties::LEFT + numwallsMinusOne].tick(filterInputSamp);
2877  break;
2878  case Properties::RIGHT_CEILING:
2879  ceilSamps += walls[k][Properties::RIGHT + numwallsMinusOne].tick(filterInputSamp);
2880  break;
2881  case Properties::FRONT_CEILING:
2882  ceilSamps += walls[k][Properties::FRONT + numwallsMinusOne].tick(filterInputSamp);
2883  break;
2884  case Properties::REAR_CEILING:
2885  ceilSamps += walls[k][Properties::REAR + numwallsMinusOne].tick(filterInputSamp);
2886  break;
2887 
2888  case Properties::LEFT_FRONT:
2889  frontSamps += walls[k][Properties::LEFT + numwallsMinusOne].tick(filterInputSamp);
2890  break;
2891  case Properties::RIGHT_FRONT:
2892  frontSamps += walls[k][Properties::RIGHT + numwallsMinusOne].tick(filterInputSamp);
2893  break;
2894 
2895  case Properties::LEFT_REAR:
2896  rearSamps += walls[k][Properties::LEFT + numwallsMinusOne].tick(filterInputSamp);
2897  break;
2898  case Properties::RIGHT_REAR:
2899  rearSamps += walls[k][Properties::RIGHT + numwallsMinusOne].tick(filterInputSamp);
2900  break;
2901 
2902  case Properties::AIR: // filtered direct sound
2903  outs[k][n] += filterInputSamp;
2904  break;
2905 
2906  // after one reflection
2907  case Properties::LEFT:
2908  reflSamps += walls[k][0].tick(filterInputSamp); // sum first order reflections [Properties::LEFT - 1]
2909  outs[k][n] += air[k][0].tick(reflSamps); // reflections are filtered by air absorption LPF
2910  break;
2911 
2912  case Properties::RIGHT:
2913  reflSamps += walls[k][1].tick(filterInputSamp); // sum first order reflections [Properties::RIGHT - 1]
2914  break;
2915 
2916 
2917  case Properties::FRONT:
2918  frontSamps += filterInputSamp;
2919  reflSamps += walls[k][2].tick(frontSamps); // write reflections to output [Properties::FRONT - 1]
2920  break;
2921 
2922  case Properties::REAR:
2923  rearSamps += filterInputSamp;
2924  reflSamps += walls[k][3].tick(rearSamps); // write reflections to output [Properties::REAR - 1]
2925  break;
2926 
2927  case Properties::FLOOR:
2928  floorSamps += filterInputSamp;
2929  reflSamps += walls[k][4].tick(floorSamps); // write reflections to output [FLOOR - 1]
2930  break;
2931 
2932  case Properties::CEILING:
2933  ceilSamps += filterInputSamp;
2934  reflSamps += walls[k][5].tick(ceilSamps); // write first order reflection to output [CEILING - 1]
2935  break;
2936  }
2937  }
2938  }
2939  }
2940  }
2941  } // end of while
2942  }
2943  bp += sampleframes;
2944  if (bp >= ep) // return pointer to start when it arrives at the end. TM: changed == to >=
2945  x->c_phase = 0;
2946  else
2947  x->c_phase = phase + sampleframes;
2948 
2949  if (x->grainCounter < renderInterval)
2950  x->grainCounter++;
2951  break;
2952  ////////////////////////////////////////////////////////////////////////////////
2953 
2954  case Properties::X_FADE_LITE: // with crossfade between delay
2955 
2956  for (int n=0 ; n < sampleframes; n++)
2957  {
2958  if (fades->isActive()) // we're crossfading!
2959  {
2960  for (int k = 0; k < numChannels; ++k)
2961  {
2962  oldSamp = newSamp = 0.0;
2963  outs[k][n] = 0.0;
2964  newReflSamps = 0.0;
2965  oldReflSamps= 0.0;
2966 
2967  if (micGainNonZero[k])
2968  {
2969  for (int reflNum = maxDynRefl - 1; reflNum >= Properties::DIRECT; --reflNum) // TM: if x->maxDynRefl is always same as x->numRefl, why is it necessary?
2970  {
2971  reflOrderIndex = reflNum + maxDynRefl * k;
2972 
2973  idelay = *(delay + reflOrderIndex) - 0.5;
2974  idelayOld = *(currentDelay + reflOrderIndex) - 0.5;
2975 
2976  switch (reflNum)
2977  {
2978  // direct sound
2979  case 0:
2980  oldSamp = *(currentSensitivity + reflOrderIndex) * *(bp + Properties::DELAYSIZE - idelayOld);
2981  newSamp = *(sensitivity + reflOrderIndex) * *(bp + Properties::DELAYSIZE - idelay);
2982  outs[k][n] += fades->tick(newSamp, oldSamp); // write cross fade of signals to output
2983  break;
2984 
2985  // 1st order reflections, filtered by walls and air absorption
2986  case 1:
2987  oldReflSamps += *(currentSensitivity + reflOrderIndex) * *(bp + Properties::DELAYSIZE - idelayOld);
2988  newReflSamps += *(sensitivity + reflOrderIndex) * *(bp + Properties::DELAYSIZE - idelay);
2989 
2990  outs[k][n] = xfadeWalls[k][0].tick(outs[k][n] + fades->tick(newReflSamps, oldReflSamps));
2991  outs[k][n] = xfadeAir[k].tick(outs[k][n]); // filter all by air filter
2992  break;
2993 
2994  // 2nd order reflections
2995  case 7:
2996  oldReflSamps += *(currentSensitivity + reflOrderIndex) * *(bp + Properties::DELAYSIZE - idelayOld);
2997  newReflSamps += *(sensitivity + reflOrderIndex) * *(bp + Properties::DELAYSIZE - idelay);
2998 
2999  outs[k][n] = xfadeWalls[k][1].tick(fades->tick(newReflSamps, oldReflSamps));
3000  newReflSamps = 0.0;
3001  oldReflSamps = 0.0;
3002  break;
3003 
3004  default:
3005  oldReflSamps += *(currentSensitivity + reflOrderIndex) * *(bp + Properties::DELAYSIZE - idelayOld);
3006  newReflSamps += *(sensitivity + reflOrderIndex) * *(bp + Properties::DELAYSIZE - idelay);
3007  break;
3008  }
3009  }
3010  }
3011  }
3012 
3013  fades->increment(); // update crossfade counters by one sample
3014  // TM: Don't take anything else out of this
3015  if (!fades->isActive()) // if done crossfading
3016  {
3017  for (int k = 0; k < numChannels; ++k)
3018  {
3019  numOfReflTimesK = numOfRefl * k;
3020  for (int reflNum = maxDynRefl - 1; reflNum >= Properties::DIRECT; --reflNum) // TM: if x->maxDynRefl is always same as x->numRefl, why is it necessary?
3021  {
3022  reflOrderIndex = reflNum + numOfReflTimesK;//maxDynRefl * k;
3023  *(currentDelay + reflOrderIndex) = *(delay + reflOrderIndex); // Update delays and sensitivities
3024  *(currentSensitivity + reflOrderIndex) = *(sensitivity + reflOrderIndex);
3025  }
3026  }
3027  }
3028 
3029  for (int reflNum = 0 ; reflNum < numChannels * numOfRefl ; ++reflNum) //NP: not sure if we need this for X-fade methods...
3030  { //We need to update the Sensi and Delay vector so that in case for a new bang, the correct grains can be calculated
3031  x->currentSensitivity[reflNum] = *(currentSensitivity + reflNum);
3032  x->currentDelay[reflNum] = *(currentDelay + reflNum);
3033  }
3034 
3035  }
3036  else // steady state, not crossfading
3037  {
3038  for (int k = 0; k < numChannels; ++k)
3039  {
3040  outs[k][n] = 0.0;
3041  reflSamps = 0.0;
3042  numOfReflTimesK = numOfRefl * k;
3043  if (micGainNonZero[k])
3044  {
3045  for (int reflNum = numOfRefl - 1; reflNum >= Properties::DIRECT; --reflNum) // iterate backward through reflections, to filter
3046  {
3047  reflOrderIndex = reflNum +numOfReflTimesK;
3048 
3049  // update sensitivity
3050  if (GrainCounter < renderInterval)
3051  *(currentSensitivity + reflOrderIndex) += *(sensiGrain + reflOrderIndex);
3052  else
3053  {
3054  *(currentDelay + reflOrderIndex) = *(delay + reflOrderIndex); // Update delay time
3055  *(currentSensitivity + reflOrderIndex) = *(sensitivity + reflOrderIndex);
3056  }
3057 
3058  idelay = *(currentDelay + reflOrderIndex) - 0.5;
3059 
3060  switch (reflNum)
3061  {
3062  case Properties::DIRECT:
3063  outs[k][n] = (*(currentSensitivity + reflOrderIndex) *
3064  *(bp + Properties::DELAYSIZE - idelay)) + reflSamps;
3065  break;
3066  // sample is filtered by first order reflection filter only and air
3067  case 1:
3068  reflSamps += (*(currentSensitivity + reflOrderIndex) *
3069  *(bp + Properties::DELAYSIZE - idelay));
3070 
3071  reflSamps = xfadeWalls[k][0].tick(reflSamps);
3072  reflSamps = xfadeAir[k].tick(reflSamps);
3073  break;
3074 
3075  case 7: // sample is filtered by 2nd order reflection filter only
3076  reflSamps += (*(currentSensitivity + reflOrderIndex) *
3077  *(bp + Properties::DELAYSIZE - idelay));
3078 
3079  reflSamps = xfadeWalls[k][1].tick(reflSamps);
3080  break;
3081 
3082  default:
3083  reflSamps += (*(currentSensitivity + reflOrderIndex) *
3084  *(bp + Properties::DELAYSIZE - idelay));
3085  break;
3086  }
3087  }
3088  }
3089  }
3090  }
3091  bp++;
3092  } // end of while
3093 
3094  if (bp >= ep) // return pointer to start when it arrives at the end. TM: changed == to >=
3095  x->c_phase = 0;
3096  else
3097  x->c_phase = phase + sampleframes;
3098 
3099  if (x->grainCounter < renderInterval)
3100  x->grainCounter++;
3101 
3102  break;
3103 /************************************************************************************************/
3104  case Properties::X_FADE_XL: // with crossfade between delay, independent filtering for each wall
3105  double oldFilterInputSamp, newFilterInputSamp;
3106 
3107  for (int n=0 ; n < sampleframes; n++)
3108  {
3109  if (fades->isActive()) // we're crossfading!
3110  {
3111  for (int k = 0; k < numChannels; ++k)
3112  {
3113  oldFilterInputSamp = newFilterInputSamp = 0.0;
3114  frontSamps = rearSamps = floorSamps = ceilSamps = reflSamps = 0.0;
3115  outs[k][n] = 0.0;
3116  numOfReflTimesK = numOfRefl * k;
3117 
3118  if (micGainNonZero[k])
3119  {
3120  for (int reflNum = maxDynRefl - 1; reflNum >= Properties::DIRECT; --reflNum)// TM: if x->maxDynRefl is always same as x->numRefl, why is it necessary?
3121  {
3122  reflOrderIndex = reflNum + numOfReflTimesK;
3123  idelay = *(delay + reflOrderIndex) - 0.5; // a bit more efficient that the two lines above
3124  idelayOld = *(currentDelay + reflOrderIndex) - 0.5;
3125 
3126  oldFilterInputSamp = *(currentSensitivity + reflOrderIndex) * *(bp + Properties::DELAYSIZE - idelayOld);
3127  newFilterInputSamp = *(sensitivity + reflOrderIndex) * *(bp + Properties::DELAYSIZE - idelay);
3128 
3129  switch (reflNum)
3130  {
3131  case Properties::FRONT_FLOOR:
3132  floorSamps += walls[k][Properties::FRONT + numwallsMinusOne].tick(fades->tick(newFilterInputSamp, oldFilterInputSamp));
3133  break;
3134  case Properties::REAR_FLOOR:
3135  floorSamps += walls[k][Properties::REAR + numwallsMinusOne].tick(fades->tick(newFilterInputSamp, oldFilterInputSamp));
3136  break;
3137  case Properties::LEFT_FLOOR:
3138  floorSamps += walls[k][Properties::LEFT + numwallsMinusOne].tick(fades->tick(newFilterInputSamp, oldFilterInputSamp));
3139  break;
3140  case Properties::RIGHT_FLOOR:
3141  floorSamps += walls[k][Properties::RIGHT + numwallsMinusOne].tick(fades->tick(newFilterInputSamp, oldFilterInputSamp));
3142  break;
3143 
3144  case Properties::LEFT_CEILING:
3145  ceilSamps += walls[k][Properties::LEFT + numwallsMinusOne].tick(fades->tick(newFilterInputSamp, oldFilterInputSamp));
3146  break;
3147  case Properties::RIGHT_CEILING:
3148  ceilSamps += walls[k][Properties::RIGHT + numwallsMinusOne].tick(fades->tick(newFilterInputSamp, oldFilterInputSamp));
3149  break;
3150  case Properties::FRONT_CEILING:
3151  ceilSamps += walls[k][Properties::FRONT + numwallsMinusOne].tick(fades->tick(newFilterInputSamp, oldFilterInputSamp));
3152  break;
3153  case Properties::REAR_CEILING:
3154  ceilSamps += walls[k][Properties::REAR + numwallsMinusOne].tick(fades->tick(newFilterInputSamp, oldFilterInputSamp));
3155  break;
3156 
3157  case Properties::LEFT_FRONT:
3158  frontSamps += walls[k][Properties::LEFT + numwallsMinusOne].tick(fades->tick(newFilterInputSamp, oldFilterInputSamp));
3159  break;
3160  case Properties::RIGHT_FRONT:
3161  frontSamps += walls[k][Properties::RIGHT + numwallsMinusOne].tick(fades->tick(newFilterInputSamp, oldFilterInputSamp));
3162  break;
3163 
3164  case Properties::LEFT_REAR:
3165  rearSamps += walls[k][Properties::LEFT + numwallsMinusOne].tick(fades->tick(newFilterInputSamp, oldFilterInputSamp));
3166  break;
3167  case Properties::RIGHT_REAR:
3168  rearSamps += walls[k][Properties::RIGHT + numwallsMinusOne].tick(fades->tick(newFilterInputSamp, oldFilterInputSamp));
3169  break;
3170 
3171  // direct sound
3172  case Properties::AIR:
3173  outs[k][n] +=fades->tick(newFilterInputSamp, oldFilterInputSamp);
3174  break;
3175 
3176  case Properties::LEFT:
3177  reflSamps = walls[k][Properties::LEFT - 1].tick(fades->tick(newFilterInputSamp, oldFilterInputSamp));
3178  outs[k][n] = walls[k][0].tick(reflSamps); // apply air filter at this last stage
3179  break;
3180 
3181  case Properties::RIGHT:
3182  reflSamps += walls[k][Properties::RIGHT - 1].tick(fades->tick(newFilterInputSamp, oldFilterInputSamp));
3183  break;
3184 
3185  case Properties::FRONT:
3186  frontSamps += fades->tick(newFilterInputSamp, oldFilterInputSamp);
3187  reflSamps += walls[k][Properties::FRONT - 1].tick(frontSamps);
3188  break;
3189 
3190  case Properties::REAR:
3191  rearSamps += fades->tick(newFilterInputSamp, oldFilterInputSamp);
3192  reflSamps += walls[k][Properties::REAR - 1].tick(rearSamps);
3193  break;
3194 
3195  case Properties::FLOOR:
3196  floorSamps += fades->tick(newFilterInputSamp, oldFilterInputSamp);
3197  reflSamps += walls[k][Properties::FLOOR - 1].tick(floorSamps);
3198  break;
3199 
3200  case Properties::CEILING:
3201  ceilSamps += fades->tick(newFilterInputSamp, oldFilterInputSamp);
3202  reflSamps += walls[k][Properties::CEILING - 1].tick(ceilSamps);
3203  break;
3204  }
3205  }
3206  }
3207  }
3208 
3209  fades->increment(); // update crossfade counters by one sample
3210 
3211  // TM: Don't take anything else out of this
3212  if (!fades->isActive()) // if done crossfading
3213  {
3214  for (int k = 0; k < numChannels; ++k)
3215  {
3216  numOfReflTimesK = numOfRefl * k;
3217  for (int reflNum = maxDynRefl - 1; reflNum >= Properties::DIRECT; --reflNum) // TM: if x->maxDynRefl is always same as x->numRefl, why is it necessary?
3218  {
3219  reflOrderIndex = reflNum + numOfReflTimesK;//maxDynRefl * k;
3220  *(currentDelay + reflOrderIndex) = *(delay + reflOrderIndex); // Update delays and sensitivities
3221  *(currentSensitivity + reflOrderIndex) = *(sensitivity + reflOrderIndex);
3222 
3223  }
3224  }
3225  }
3226 
3227  for (int reflNum = 0 ; reflNum < numChannels * numOfRefl ; ++reflNum) //NP: not sure if we need this for X-fade methods...
3228  { //We need to update the Sensi and Delay vector so that in case for a new bang, the correct grains can be calculated
3229  x->currentSensitivity[reflNum] = *(currentSensitivity + reflNum);
3230  x->currentDelay[reflNum] = *(currentDelay + reflNum);
3231  }
3232  }
3233  else // steady state, not crossfading
3234  {
3235  for (int k = 0; k < numChannels; ++k)
3236  {
3237  outs[k][n] = 0.0;
3238  reflSamps = 0.0;
3239  frontSamps = rearSamps = floorSamps = ceilSamps = reflSamps = filterInputSamp = 0.0;
3240  numOfReflTimesK = numOfRefl * k;
3241  if (micGainNonZero[k])
3242  {
3243  for (int reflNum = numOfRefl - 1; reflNum >= Properties::DIRECT; --reflNum) // iterate backward through reflections, to filter
3244  {
3245  reflOrderIndex = reflNum + numOfReflTimesK;
3246 
3247  // update sensitivity
3248  if (GrainCounter < renderInterval)
3249  *(currentSensitivity + reflOrderIndex) += *(sensiGrain + reflOrderIndex);
3250  else
3251  {
3252  *(currentSensitivity + reflOrderIndex) = *(sensitivity + reflOrderIndex);
3253  *(currentDelay + reflOrderIndex) = *(delay + reflOrderIndex); // Update delay time
3254  }
3255 
3256  idelay = *(currentDelay + reflOrderIndex) - 0.5;
3257  filterInputSamp = *(currentSensitivity + reflOrderIndex) * *(bp + Properties::DELAYSIZE - idelay);
3258 
3259  switch (reflNum) // TODO: is there a cleaner but also clear way of doing this that is as fast?
3260  {
3261  case Properties::FRONT_FLOOR:
3262  floorSamps += walls[k][Properties::FRONT + numwallsMinusOne].tick(filterInputSamp);
3263  break;
3264  case Properties::REAR_FLOOR:
3265  floorSamps += walls[k][Properties::REAR + numwallsMinusOne].tick(filterInputSamp);
3266  break;
3267  case Properties::LEFT_FLOOR:
3268  floorSamps += walls[k][Properties::LEFT + numwallsMinusOne].tick(filterInputSamp);
3269  break;
3270  case Properties::RIGHT_FLOOR:
3271  floorSamps += walls[k][Properties::RIGHT + numwallsMinusOne].tick(filterInputSamp);
3272  break;
3273 
3274  case Properties::LEFT_CEILING:
3275  ceilSamps += walls[k][Properties::LEFT + numwallsMinusOne].tick(filterInputSamp);
3276  break;
3277  case Properties::RIGHT_CEILING:
3278  ceilSamps += walls[k][Properties::RIGHT + numwallsMinusOne].tick(filterInputSamp);
3279  break;
3280  case Properties::FRONT_CEILING:
3281  ceilSamps += walls[k][Properties::FRONT + numwallsMinusOne].tick(filterInputSamp);
3282  break;
3283  case Properties::REAR_CEILING:
3284  ceilSamps += walls[k][Properties::REAR + numwallsMinusOne].tick(filterInputSamp);
3285  break;
3286 
3287  case Properties::LEFT_FRONT:
3288  frontSamps += walls[k][Properties::LEFT + numwallsMinusOne].tick(filterInputSamp);
3289  break;
3290  case Properties::RIGHT_FRONT:
3291  frontSamps += walls[k][Properties::RIGHT + numwallsMinusOne].tick(filterInputSamp);
3292  break;
3293 
3294  case Properties::LEFT_REAR:
3295  rearSamps += walls[k][Properties::LEFT + numwallsMinusOne].tick(filterInputSamp);
3296  break;
3297  case Properties::RIGHT_REAR:
3298  rearSamps += walls[k][Properties::RIGHT + numwallsMinusOne].tick(filterInputSamp);
3299  break;
3300 
3301  case Properties::DIRECT: // filtered direct sound
3302  outs[k][n] += filterInputSamp;
3303  break;
3304 
3305  // after one reflection
3306  case Properties::LEFT:
3307  reflSamps += walls[k][Properties::LEFT - 1].tick(filterInputSamp); // sum first order reflections
3308  outs[k][n] = air[k][0].tick(reflSamps);
3309  break;
3310 
3311  case Properties::RIGHT:
3312  reflSamps += walls[k][Properties::RIGHT - 1].tick(filterInputSamp); // sum first order reflections
3313  break;
3314 
3315  case Properties::FRONT:
3316  frontSamps += filterInputSamp;
3317  reflSamps += walls[k][Properties::FRONT - 1].tick(frontSamps); // write reflections to output
3318  break;
3319 
3320  case Properties::REAR:
3321  rearSamps += filterInputSamp;
3322  reflSamps += walls[k][Properties::REAR - 1].tick(rearSamps); // write reflections to output
3323  break;
3324 
3325  case Properties::FLOOR:
3326  floorSamps += filterInputSamp;
3327  reflSamps += walls[k][Properties::FLOOR - 1].tick(floorSamps); // write reflections to output
3328  break;
3329 
3330  case Properties::CEILING:
3331  ceilSamps += filterInputSamp;
3332  reflSamps += walls[k][Properties::CEILING - 1].tick(ceilSamps); // write first order reflection to output
3333  break;
3334  }
3335  }
3336  }
3337  }
3338  }
3339  bp++;
3340  } // end of while
3341 
3342  if (bp >= ep) // return pointer to start when it arrives at the end. TM: changed == to >=
3343  x->c_phase = 0;
3344  else
3345  x->c_phase = phase + sampleframes;
3346  if (x->grainCounter < renderInterval)
3347  x->grainCounter++;
3348  break;
3349 
3350 ////////////////////////////////////////////////////////////////////////////////////////////////////////////
3351  case Properties::AMP_PAN: // amplitude panning only
3352  if (GrainCounter < renderInterval) {
3353  for (int k = 0; k < numChannels; k++) {
3354  memset(outs[k], 0, sizeof(double)*sampleframes);
3355  if (micGainNonZero[k]) {
3356  reflOrderIndex = numOfRefl * k;
3357  for (int n=0 ; n < sampleframes; n++) {
3358  *(currentSensitivity + reflOrderIndex) += *(sensiGrain + reflOrderIndex);
3359  outs[k][n] = *(currentSensitivity + reflOrderIndex) * *(bp + Properties::DELAYSIZE + n);
3360  }
3361  }
3362  }
3363  for (int reflNum = 0 ; reflNum < numChannels * numOfRefl ; ++reflNum) {
3364  //We need to update the Sensi and Delay vector so that in case for a new bang, the correct grains can be calculated
3365  x->currentSensitivity[reflNum] = *(currentSensitivity + reflNum);
3366  }
3367  }
3368  else {
3369  for (int k = 0; k < numChannels; k++) {
3370  memset(outs[k], 0, sizeof(double)*sampleframes);
3371  if (micGainNonZero[k]) {
3372  reflOrderIndex = numOfRefl * k;
3373  for (int n=0 ; n < sampleframes; n++) {
3374  outs[k][n] = *(bp + Properties::DELAYSIZE + n) * *(currentSensitivity + reflOrderIndex);
3375  }
3376  }
3377  }
3378  }
3379  bp += sampleframes;
3380 
3381  if (bp >= ep) // return pointer to start when it arrives at the end. TM: changed == to >=
3382  x->c_phase = 0;
3383  else
3384  x->c_phase = phase + sampleframes;
3385 
3386  if (x->grainCounter < renderInterval)
3387  x->grainCounter++;
3388  break;
3389  ////////////////////////////////////////////////////////////////////////////////
3390  case Properties::STATIC: // Nothing moves, only integer delays
3391  if (GrainCounter < renderInterval)
3392  {
3393  for (int n=0 ; n < sampleframes; n++)
3394  {
3395  for (int k = 0; k < numChannels; ++k)
3396  {
3397  outs[k][n] = 0.0;
3398  reflSamps = 0.0;
3399  numOfReflTimesK = numOfRefl * k;
3400 
3401  if (micGainNonZero[k])
3402  {
3403  for (int reflNum = numOfRefl - 1; reflNum >= Properties::DIRECT; --reflNum)
3404  {
3405  reflOrderIndex = reflNum + numOfReflTimesK;
3406  *(currentDelay + reflOrderIndex) += *(delGrain + reflOrderIndex); // TM: Changed
3407  *(currentSensitivity + reflOrderIndex) += *(sensiGrain + reflOrderIndex);
3408  idelay = *(currentDelay + reflOrderIndex) - 0.5;
3409 
3410  switch (reflNum)
3411  {
3412  case 0:
3413  outs[k][n] = *(currentSensitivity + reflOrderIndex) * *(bp + Properties::DELAYSIZE - idelay) + reflSamps;
3414  break;
3415 
3416  case 1:
3417  reflSamps += *(currentSensitivity + reflOrderIndex) * *(bp + Properties::DELAYSIZE - idelay);
3418  reflSamps = air[k][0].tick(walls[k][0].tick(reflSamps));
3419  break;
3420 
3421  case 7:
3422  reflSamps += *(currentSensitivity + reflOrderIndex) * *(bp + Properties::DELAYSIZE - idelay);
3423  reflSamps = walls[k][6].tick(reflSamps);
3424  break;
3425 
3426  default:
3427  reflSamps += *(currentSensitivity + reflOrderIndex) * *(bp + Properties::DELAYSIZE - idelay);
3428  break;
3429  }
3430  }
3431  }
3432  }
3433  bp++;
3434  } // end of while
3435 
3436  for (int reflNum = 0 ; reflNum < numChannels * numOfRefl ; ++reflNum)
3437  { //We need to update the Sensi and Delay vector so that in case for a new bang, the correct grains can be calculated
3438  x->currentSensitivity[reflNum] = *(currentSensitivity + reflNum);
3439  x->currentDelay[reflNum] = *(currentDelay + reflNum);
3440  }
3441 
3442  }
3443  else // steady state
3444  {
3445  for (int n=0 ; n < sampleframes; n++)
3446  {
3447  for (int k=0; k < numChannels; ++k)
3448  {
3449  outs[k][n] = 0.0;
3450  reflSamps = 0.0;
3451  numOfReflTimesK = numOfRefl * k;
3452 
3453  if (micGainNonZero[k])
3454  {
3455  for (int reflNum = numOfRefl - 1; reflNum >= Properties::DIRECT; --reflNum)
3456  {
3457  reflOrderIndex = reflNum + numOfReflTimesK;
3458  idelay = *(currentDelay + reflOrderIndex) - 0.5;
3459 
3460  switch (reflNum)
3461  {
3462  case 0:
3463  outs[k][n] = *(currentSensitivity + reflOrderIndex) * *(bp + Properties::DELAYSIZE - idelay) + reflSamps;
3464  break;
3465 
3466  case 1:
3467  reflSamps += *(currentSensitivity + reflOrderIndex) * *(bp + Properties::DELAYSIZE - idelay);
3468  reflSamps = air[k][0].tick(walls[k][0].tick(reflSamps));
3469  break;
3470 
3471  case 7:
3472  reflSamps += *(currentSensitivity + reflOrderIndex) * *(bp + Properties::DELAYSIZE - idelay);
3473  reflSamps = walls[k][6].tick(reflSamps);
3474  break;
3475 
3476  default:
3477  reflSamps += *(currentSensitivity + reflOrderIndex) * *(bp + Properties::DELAYSIZE - idelay);
3478  break;
3479  }
3480  }
3481  }
3482  }
3483  bp++;
3484  } // end of while
3485  }
3486  if (bp >= ep) // return pointer to start when it arrives at the end. TM: changed == to >=
3487  x->c_phase = 0;
3488  else
3489  x->c_phase = phase + sampleframes;
3490  if (x->grainCounter < renderInterval)
3491  x->grainCounter++;
3492  break;
3493  /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3494 
3495  case Properties::NONE: // no audio
3496  bp += sampleframes;
3497  for (int k = 0; k < numChannels; k++) {
3498  memset(outs[k], 0, sizeof(double) * sampleframes);
3499  }
3500  bp += sampleframes;
3501  if (bp >= ep) // return pointer to start when it arrives at the end. TM: changed == to >=
3502  x->c_phase = 0;
3503  else
3504  x->c_phase = phase + sampleframes;
3505 
3506  if (x->grainCounter < renderInterval)
3507  x->grainCounter++;
3508  break;
3509  }
3510 
3511 }
3512 
3513 void vimic_dsp64(t_vimic *x, t_object *dsp64, short *count, double samplerate, long maxvectorsize, long flags)
3514 {
3515  // clear out the delay line
3516  for (int n = 0; n < Properties::DELAYBYTES; n++)
3517  x->c_vec[n] = 0.0;
3518 
3519  if (x->x_sr != samplerate)
3520  {
3521  x->x_sr = samplerate;
3522  x->speedOfSound = (331.3 * sqrt(1.0 + x->temperature / 273.15)) / x->x_sr;
3523  x->invSpeedOfSound = 1.0 / x->speedOfSound;
3524  }
3525 
3526  if (x->blocksize != (int)maxvectorsize) {
3527  x->blocksize = (int)maxvectorsize;
3528  x->grainsize = 1.0 / (x->blocksize * x->renderInterval);
3529  }
3530 
3531  object_method(dsp64, gensym("dsp_add64"), x, vimic_perform64, 0, NULL);
3532 }
bool isActive() const
True if a crossfade is underway, false othewise.
HiMidLow filter class.
Definition: HiMidLow.h:22
Jamoma DSP Library.
double tick(double input)
Given an input sample, returns a filtered output sample.
Definition: Filter.h:65
Low pass filter class.
Definition: LowPass.h:22
CrossFadeQueue class.
void TTDSP_EXPORT TTDSPInit(const char *pathToBinaries=NULL)
Initialise the Jamoma DSP library, as well as Jamoma Foundation foundation if needed.
Definition: TTDSP.cpp:30
void increment()
Increment top level crossfade.
double tick(double fadeInInput, double fadeOutInput)
Out value of crossfade.
Room class.
Definition: Room.h:25