/* For information on usage and redistribution, and for a DISCLAIMER OF ALL
* WARRANTIES, see the file, "LICENSE.txt," in this distribution.

iem_roomsim written by Thomas Musil (c) IEM KUG Graz Austria 2002 - 2018 */

#include "m_pd.h"
#include "iemlib.h"
#include <math.h>


/* -------------------------- xy_2_del_damp_phi ------------------------------ */
/*
**  pos. x-Richtung Nase
**  pos. y-Richtung Linke Hand
**  pos. z-Richtung Scheitel
**  Kartesischer Koordinaten-Ursprung liegt in der Mitte des Raums am Boden

  aenderungen: src-index von 1 .. n auf 0 .. (n-1)
  aenderungen: azimuth von rad auf degree
*/

/*

    
    1., 2., 3. und 4. reflexionen:


            +y
             ^
             |
             |
             29
          30 16 28
       31 17 07 15 27
    32 18 08 02 06 14 26
 33 19 09 03 00 01 05 13 25 ---> +x
    34 20 10 04 12 24 40
       35 21 11 23 39
          36 22 38
             37

*/



typedef struct _xy_2_del_damp_phi
{
  t_object  x_obj;
  t_symbol  *x_s_direct;
  t_symbol  *x_s_early1;
  t_symbol  *x_s_early2;
  t_symbol  *x_s_early3;
  t_symbol  *x_s_early4;
  t_symbol  *x_s_del;
  t_symbol  *x_s_damp;
  t_symbol  *x_s_phi;
  t_float   x_room_x;
  t_float   x_room_y;
  t_float   x_head_x;
  t_float   x_head_y;
  t_float   x_src_x;
  t_float   x_src_y;
  t_float   x_r_min;
  t_float   x_speed;
  t_float   x_180_over_pi;
  t_float   *x_rad;
  t_atom    *x_at;
  t_int     x_size_rad;
  t_int     x_size_at;
  void      *x_clock;
} t_xy_2_del_damp_phi;

static t_class *xy_2_del_damp_phi_class;

static t_float xy_2_del_damp_phi_calc_radius(t_float r_min, t_float dx, t_float dy)
{
  t_float r = (t_float)sqrt(dx*dx + dy*dy);
  
  if(r < r_min)
    return(r_min);
  else
    return(r);
}

static t_float xy_2_del_damp_phi_calc_azimuth(t_float x_180_over_pi, t_float dx, t_float dy)
{
  if(dx == 0.0f)
  {
    if(dy < 0.0f)
      return(270.0f);
    else
      return(90.0f);
  }
  else if(dx < 0.0f)
  {
    return(180.0f + x_180_over_pi * (t_float)atan(dy / dx));
  }
  else
  {
    if(dy < 0.0f)
      return(360.0f + x_180_over_pi * (t_float)atan(dy / dx));
    else
      return(x_180_over_pi * (t_float)atan(dy / dx));
  }
}

static void xy_2_del_damp_phi_doit(t_xy_2_del_damp_phi *x)
{
  t_float diff_x, diff_y;
  t_float sum_x, sum_y;
  t_float lx, wy;
  t_float x_0, y_0;
  t_float xp1, yp1, xn1, yn1;
  t_float xp2, yp2, xn2, yn2;
  t_float xp3, yp3, xn3, yn3;
  t_float xp4, yp4, xn4, yn4;
  t_float m2ms = 1000.0f / x->x_speed;
  t_float x_180_over_pi=x->x_180_over_pi;
  t_float r_min = x->x_r_min;
  t_float *rad=x->x_rad;
  t_atom *at=x->x_at;
  
  lx = x->x_room_x;
  wy = x->x_room_y;
  
  diff_x = x->x_src_x - x->x_head_x;
  diff_y = x->x_src_y - x->x_head_y;
  sum_x = x->x_src_x + x->x_head_x;
  sum_y = x->x_src_y + x->x_head_y;
  
  x_0 = diff_x;
  y_0 = diff_y;
  xp1 = lx - sum_x;
  yp1 = wy - sum_y;
  xn1 = -lx - sum_x;
  yn1 = -wy - sum_y;
  xp2 = 2.0f*lx + diff_x;
  yp2 = 2.0f*wy + diff_y;
  xn2 = -2.0f*lx + diff_x;
  yn2 = -2.0f*wy + diff_y;
  xp3 = 3.0f*lx - sum_x;
  yp3 = 3.0f*wy - sum_y;
  xn3 = -3.0f*lx - sum_x;
  yn3 = -3.0f*wy - sum_y;
  xp4 = 4.0f*lx + diff_x;
  yp4 = 4.0f*wy + diff_y;
  xn4 = -4.0f*lx + diff_x;
  yn4 = -4.0f*wy + diff_y;
  
  rad[0] = xy_2_del_damp_phi_calc_radius(r_min, x_0, y_0);

  rad[1] = xy_2_del_damp_phi_calc_radius(r_min, xp1, y_0);
  rad[2] = xy_2_del_damp_phi_calc_radius(r_min, x_0, yp1);
  rad[3] = xy_2_del_damp_phi_calc_radius(r_min, xn1, y_0);
  rad[4] = xy_2_del_damp_phi_calc_radius(r_min, x_0, yn1);

  rad[5] = xy_2_del_damp_phi_calc_radius(r_min, xp2, y_0);
  rad[6] = xy_2_del_damp_phi_calc_radius(r_min, xp1, yp1);
  rad[7] = xy_2_del_damp_phi_calc_radius(r_min, x_0, yp2);
  rad[8] = xy_2_del_damp_phi_calc_radius(r_min, xn1, yn1);
  rad[9] = xy_2_del_damp_phi_calc_radius(r_min, xn2, y_0);
  rad[10] = xy_2_del_damp_phi_calc_radius(r_min, xp1, yn1);
  rad[11] = xy_2_del_damp_phi_calc_radius(r_min, x_0, yn2);
  rad[12] = xy_2_del_damp_phi_calc_radius(r_min, xn1, yp1);

  rad[13] = xy_2_del_damp_phi_calc_radius(r_min, xp3, y_0);
  rad[14] = xy_2_del_damp_phi_calc_radius(r_min, xp2, yp1);
  rad[15] = xy_2_del_damp_phi_calc_radius(r_min, xp1, yp2);
  rad[16] = xy_2_del_damp_phi_calc_radius(r_min, x_0, yp3);
  rad[17] = xy_2_del_damp_phi_calc_radius(r_min, xn1, yp2);
  rad[18] = xy_2_del_damp_phi_calc_radius(r_min, xn2, yp1);
  rad[19] = xy_2_del_damp_phi_calc_radius(r_min, xn3, y_0);
  rad[20] = xy_2_del_damp_phi_calc_radius(r_min, xn2, yn1);
  rad[21] = xy_2_del_damp_phi_calc_radius(r_min, xn1, yn2);
  rad[22] = xy_2_del_damp_phi_calc_radius(r_min, x_0, yn3);
  rad[23] = xy_2_del_damp_phi_calc_radius(r_min, xp1, yn2);
  rad[24] = xy_2_del_damp_phi_calc_radius(r_min, xp2, yn1);

  rad[25] = xy_2_del_damp_phi_calc_radius(r_min, xp4, y_0);
  rad[26] = xy_2_del_damp_phi_calc_radius(r_min, xp3, yp1);
  rad[27] = xy_2_del_damp_phi_calc_radius(r_min, xp2, yp2);
  rad[28] = xy_2_del_damp_phi_calc_radius(r_min, xp1, yp3);
  rad[29] = xy_2_del_damp_phi_calc_radius(r_min, x_0, yp4);
  rad[30] = xy_2_del_damp_phi_calc_radius(r_min, xn1, yp3);
  rad[31] = xy_2_del_damp_phi_calc_radius(r_min, xn2, yp2);
  rad[32] = xy_2_del_damp_phi_calc_radius(r_min, xn3, yp1);
  rad[33] = xy_2_del_damp_phi_calc_radius(r_min, xn4, y_0);
  rad[34] = xy_2_del_damp_phi_calc_radius(r_min, xn3, yn1);
  rad[35] = xy_2_del_damp_phi_calc_radius(r_min, xn2, yn2);
  rad[36] = xy_2_del_damp_phi_calc_radius(r_min, xn1, yn3);
  rad[37] = xy_2_del_damp_phi_calc_radius(r_min, x_0, yn4);
  rad[38] = xy_2_del_damp_phi_calc_radius(r_min, xp1, yn3);
  rad[39] = xy_2_del_damp_phi_calc_radius(r_min, xp2, yn2);
  rad[40] = xy_2_del_damp_phi_calc_radius(r_min, xp3, yn1);
  
  /* delay-reihenfolge: 0,
  +1x, +1y, -1x, -1y
  +2x, +2y, -2x, -2y
  +1x+1y, -1x-1y
  +1x-1y, -1x+1y
  */
  
  SETSYMBOL(at, x->x_s_del);
  
  SETFLOAT(at+1, rad[0] * m2ms);
  outlet_anything(x->x_obj.ob_outlet, x->x_s_direct, 2, at);
  
  SETFLOAT(at+1, rad[1] * m2ms);
  SETFLOAT(at+2, rad[2] * m2ms);
  SETFLOAT(at+3, rad[3] * m2ms);
  SETFLOAT(at+4, rad[4] * m2ms);
  outlet_anything(x->x_obj.ob_outlet, x->x_s_early1, 5, at);
  
  SETFLOAT(at+1, rad[5] * m2ms);
  SETFLOAT(at+2, rad[6] * m2ms);
  SETFLOAT(at+3, rad[7] * m2ms);
  SETFLOAT(at+4, rad[8] * m2ms);
  SETFLOAT(at+5, rad[9] * m2ms);
  SETFLOAT(at+6, rad[10] * m2ms);
  SETFLOAT(at+7, rad[11] * m2ms);
  SETFLOAT(at+8, rad[12] * m2ms);
  outlet_anything(x->x_obj.ob_outlet, x->x_s_early2, 9, at);

  SETFLOAT(at+1, rad[13] * m2ms);
  SETFLOAT(at+2, rad[14] * m2ms);
  SETFLOAT(at+3, rad[15] * m2ms);
  SETFLOAT(at+4, rad[16] * m2ms);
  SETFLOAT(at+5, rad[17] * m2ms);
  SETFLOAT(at+6, rad[18] * m2ms);
  SETFLOAT(at+7, rad[19] * m2ms);
  SETFLOAT(at+8, rad[20] * m2ms);
  SETFLOAT(at+9, rad[21] * m2ms);
  SETFLOAT(at+10, rad[22] * m2ms);
  SETFLOAT(at+11, rad[23] * m2ms);
  SETFLOAT(at+12, rad[24] * m2ms);
  outlet_anything(x->x_obj.ob_outlet, x->x_s_early3, 13, at);

  SETFLOAT(at+1, rad[25] * m2ms);
  SETFLOAT(at+2, rad[26] * m2ms);
  SETFLOAT(at+3, rad[27] * m2ms);
  SETFLOAT(at+4, rad[28] * m2ms);
  SETFLOAT(at+5, rad[29] * m2ms);
  SETFLOAT(at+6, rad[30] * m2ms);
  SETFLOAT(at+7, rad[31] * m2ms);
  SETFLOAT(at+8, rad[32] * m2ms);
  SETFLOAT(at+9, rad[33] * m2ms);
  SETFLOAT(at+10, rad[34] * m2ms);
  SETFLOAT(at+11, rad[35] * m2ms);
  SETFLOAT(at+12, rad[36] * m2ms);
  SETFLOAT(at+13, rad[37] * m2ms);
  SETFLOAT(at+14, rad[38] * m2ms);
  SETFLOAT(at+15, rad[39] * m2ms);
  SETFLOAT(at+16, rad[40] * m2ms);
  outlet_anything(x->x_obj.ob_outlet, x->x_s_early4, 17, at);
  
  
  /* daempfungs-reihenfolge:
  0,
  +1x, +1y, -1x, -1y
  +2x, +2y, -2x, -2y
  +1x+1y, -1x-1y
  +1x-1y, -1x+1y
  */
  
  SETSYMBOL(at, x->x_s_damp);
  
  SETFLOAT(at+1, r_min / rad[0]);
  outlet_anything(x->x_obj.ob_outlet, x->x_s_direct, 2, at);
  
  SETFLOAT(at+1, r_min / rad[1]);
  SETFLOAT(at+2, r_min / rad[2]);
  SETFLOAT(at+3, r_min / rad[3]);
  SETFLOAT(at+4, r_min / rad[4]);
  outlet_anything(x->x_obj.ob_outlet, x->x_s_early1, 5, at);
  
  SETFLOAT(at+1, r_min / rad[5]);
  SETFLOAT(at+2, r_min / rad[6]);
  SETFLOAT(at+3, r_min / rad[7]);
  SETFLOAT(at+4, r_min / rad[8]);
  SETFLOAT(at+5, r_min / rad[9]);
  SETFLOAT(at+6, r_min / rad[10]);
  SETFLOAT(at+7, r_min / rad[11]);
  SETFLOAT(at+8, r_min / rad[12]);
  outlet_anything(x->x_obj.ob_outlet, x->x_s_early2, 9, at);

  SETFLOAT(at+1, r_min / rad[13]);
  SETFLOAT(at+2, r_min / rad[14]);
  SETFLOAT(at+3, r_min / rad[15]);
  SETFLOAT(at+4, r_min / rad[16]);
  SETFLOAT(at+5, r_min / rad[17]);
  SETFLOAT(at+6, r_min / rad[18]);
  SETFLOAT(at+7, r_min / rad[19]);
  SETFLOAT(at+8, r_min / rad[20]);
  SETFLOAT(at+9, r_min / rad[21]);
  SETFLOAT(at+10, r_min / rad[22]);
  SETFLOAT(at+11, r_min / rad[23]);
  SETFLOAT(at+12, r_min / rad[24]);
  outlet_anything(x->x_obj.ob_outlet, x->x_s_early3, 13, at);

  SETFLOAT(at+1, r_min / rad[25]);
  SETFLOAT(at+2, r_min / rad[26]);
  SETFLOAT(at+3, r_min / rad[27]);
  SETFLOAT(at+4, r_min / rad[28]);
  SETFLOAT(at+5, r_min / rad[29]);
  SETFLOAT(at+6, r_min / rad[30]);
  SETFLOAT(at+7, r_min / rad[31]);
  SETFLOAT(at+8, r_min / rad[32]);
  SETFLOAT(at+9, r_min / rad[33]);
  SETFLOAT(at+10, r_min / rad[34]);
  SETFLOAT(at+11, r_min / rad[35]);
  SETFLOAT(at+12, r_min / rad[36]);
  SETFLOAT(at+13, r_min / rad[37]);
  SETFLOAT(at+14, r_min / rad[38]);
  SETFLOAT(at+15, r_min / rad[39]);
  SETFLOAT(at+16, r_min / rad[40]);
  outlet_anything(x->x_obj.ob_outlet, x->x_s_early4, 17, at);
  
  
  /* encoder-winkel-reihenfolge: index delta phi
  0,
  +1x, +1y, -1x, -1y
  +2x, +2y, -2x, -2y
  +1x+1y, -1x-1y
  +1x-1y, -1x+1y
  */
  
  SETSYMBOL(at, x->x_s_phi);

  SETFLOAT(at+1, xy_2_del_damp_phi_calc_azimuth(x_180_over_pi, x_0, y_0));
  outlet_anything(x->x_obj.ob_outlet, x->x_s_direct, 2, at);
  
  SETFLOAT(at+1, xy_2_del_damp_phi_calc_azimuth(x_180_over_pi, xp1, y_0));
  SETFLOAT(at+2, xy_2_del_damp_phi_calc_azimuth(x_180_over_pi, x_0, yp1));
  SETFLOAT(at+3, xy_2_del_damp_phi_calc_azimuth(x_180_over_pi, xn1, y_0));
  SETFLOAT(at+4, xy_2_del_damp_phi_calc_azimuth(x_180_over_pi, x_0, yn1));
  outlet_anything(x->x_obj.ob_outlet, x->x_s_early1, 5, at);
  
  SETFLOAT(at+1, xy_2_del_damp_phi_calc_azimuth(x_180_over_pi, xp2, y_0));
  SETFLOAT(at+2, xy_2_del_damp_phi_calc_azimuth(x_180_over_pi, xp1, yp1));
  SETFLOAT(at+3, xy_2_del_damp_phi_calc_azimuth(x_180_over_pi, x_0, yp2));
  SETFLOAT(at+4, xy_2_del_damp_phi_calc_azimuth(x_180_over_pi, xn1, yn1));
  SETFLOAT(at+5, xy_2_del_damp_phi_calc_azimuth(x_180_over_pi, xn2, y_0));
  SETFLOAT(at+6, xy_2_del_damp_phi_calc_azimuth(x_180_over_pi, xp1, yn1));
  SETFLOAT(at+7, xy_2_del_damp_phi_calc_azimuth(x_180_over_pi, x_0, yn2));
  SETFLOAT(at+8, xy_2_del_damp_phi_calc_azimuth(x_180_over_pi, xn1, yp1));
  outlet_anything(x->x_obj.ob_outlet, x->x_s_early2, 9, at);
  
  SETFLOAT(at+1, xy_2_del_damp_phi_calc_azimuth(x_180_over_pi, xp3, y_0));
  SETFLOAT(at+2, xy_2_del_damp_phi_calc_azimuth(x_180_over_pi, xp2, yp1));
  SETFLOAT(at+3, xy_2_del_damp_phi_calc_azimuth(x_180_over_pi, xp1, yp2));
  SETFLOAT(at+4, xy_2_del_damp_phi_calc_azimuth(x_180_over_pi, x_0, yp3));
  SETFLOAT(at+5, xy_2_del_damp_phi_calc_azimuth(x_180_over_pi, xn1, yp2));
  SETFLOAT(at+6, xy_2_del_damp_phi_calc_azimuth(x_180_over_pi, xn2, yp1));
  SETFLOAT(at+7, xy_2_del_damp_phi_calc_azimuth(x_180_over_pi, xn3, y_0));
  SETFLOAT(at+8, xy_2_del_damp_phi_calc_azimuth(x_180_over_pi, xn2, yn1));
  SETFLOAT(at+9, xy_2_del_damp_phi_calc_azimuth(x_180_over_pi, xn1, yn2));
  SETFLOAT(at+10, xy_2_del_damp_phi_calc_azimuth(x_180_over_pi, x_0, yn3));
  SETFLOAT(at+11, xy_2_del_damp_phi_calc_azimuth(x_180_over_pi, xp1, yn2));
  SETFLOAT(at+12, xy_2_del_damp_phi_calc_azimuth(x_180_over_pi, xp2, yn1));
  outlet_anything(x->x_obj.ob_outlet, x->x_s_early3, 13, at);
  
  SETFLOAT(at+1, xy_2_del_damp_phi_calc_azimuth(x_180_over_pi, xp4, y_0));
  SETFLOAT(at+2, xy_2_del_damp_phi_calc_azimuth(x_180_over_pi, xp3, yp1));
  SETFLOAT(at+3, xy_2_del_damp_phi_calc_azimuth(x_180_over_pi, xp2, yp2));
  SETFLOAT(at+4, xy_2_del_damp_phi_calc_azimuth(x_180_over_pi, xp1, yp3));
  SETFLOAT(at+5, xy_2_del_damp_phi_calc_azimuth(x_180_over_pi, x_0, yp4));
  SETFLOAT(at+6, xy_2_del_damp_phi_calc_azimuth(x_180_over_pi, xn1, yp3));
  SETFLOAT(at+7, xy_2_del_damp_phi_calc_azimuth(x_180_over_pi, xn2, yp2));
  SETFLOAT(at+8, xy_2_del_damp_phi_calc_azimuth(x_180_over_pi, xn3, yp1));
  SETFLOAT(at+9, xy_2_del_damp_phi_calc_azimuth(x_180_over_pi, xn4, y_0));
  SETFLOAT(at+10, xy_2_del_damp_phi_calc_azimuth(x_180_over_pi, xn3, yn1));
  SETFLOAT(at+11, xy_2_del_damp_phi_calc_azimuth(x_180_over_pi, xn2, yn2));
  SETFLOAT(at+12, xy_2_del_damp_phi_calc_azimuth(x_180_over_pi, xn1, yn3));
  SETFLOAT(at+13, xy_2_del_damp_phi_calc_azimuth(x_180_over_pi, x_0, yn4));
  SETFLOAT(at+14, xy_2_del_damp_phi_calc_azimuth(x_180_over_pi, xp1, yn3));
  SETFLOAT(at+15, xy_2_del_damp_phi_calc_azimuth(x_180_over_pi, xp2, yn2));
  SETFLOAT(at+16, xy_2_del_damp_phi_calc_azimuth(x_180_over_pi, xp3, yn1));
  outlet_anything(x->x_obj.ob_outlet, x->x_s_early4, 17, at);
}

static void xy_2_del_damp_phi_src_xy(t_xy_2_del_damp_phi *x, t_symbol *s, int argc, t_atom *argv)
{
  if((argc >= 2)&&IS_A_FLOAT(argv, 0)&&IS_A_FLOAT(argv, 1))
  {
    t_float xr2=0.5f*x->x_room_x, yr2=0.5f*x->x_room_y;
    
    x->x_src_x = atom_getfloat(argv++);
    x->x_src_y = atom_getfloat(argv);
    if(x->x_src_x > xr2)
      x->x_src_x = xr2;
    if(x->x_src_x < -xr2)
      x->x_src_x = -xr2;
    if(x->x_src_y > yr2)
      x->x_src_y = yr2;
    if(x->x_src_y < -yr2)
      x->x_src_y = -yr2;
    clock_delay(x->x_clock, 0.0f);
  }
}

static void xy_2_del_damp_phi_head_xy(t_xy_2_del_damp_phi *x, t_symbol *s, int argc, t_atom *argv)
{
  if((argc >= 2)&&IS_A_FLOAT(argv, 0)&&IS_A_FLOAT(argv, 1))
  {
    t_float xr2=0.5f*x->x_room_x, yr2=0.5f*x->x_room_y;
    
    x->x_head_x = atom_getfloat(argv++);
    x->x_head_y = atom_getfloat(argv);
    if(x->x_head_x > xr2)
      x->x_head_x = xr2;
    if(x->x_head_x < -xr2)
      x->x_head_x = -xr2;
    if(x->x_head_y > yr2)
      x->x_head_y = yr2;
    if(x->x_head_y < -yr2)
      x->x_head_y = -yr2;
    clock_delay(x->x_clock, 0.0f);
  }
}

static void xy_2_del_damp_phi_room_xy(t_xy_2_del_damp_phi *x, t_symbol *s, int argc, t_atom *argv)
{
  if((argc >= 2)&&IS_A_FLOAT(argv, 0)&&IS_A_FLOAT(argv, 1))
  {
    t_float xr2=0.0f, yr2=0.0f;

    x->x_room_x = atom_getfloat(argv++);
    x->x_room_y = atom_getfloat(argv);
    if(x->x_room_x < 0.5f)
      x->x_room_x = 0.5f;
    if(x->x_room_y < 0.5f)
      x->x_room_y = 0.5f;

    xr2 = 0.5f*x->x_room_x;
    yr2 = 0.5f*x->x_room_y;

    if(x->x_src_x > xr2)
      x->x_src_x = xr2;
    if(x->x_src_x < -xr2)
      x->x_src_x = -xr2;
    if(x->x_src_y > yr2)
      x->x_src_y = yr2;
    if(x->x_src_y < -yr2)
      x->x_src_y = -yr2;

    if(x->x_head_x > xr2)
      x->x_head_x = xr2;
    if(x->x_head_x < -xr2)
      x->x_head_x = -xr2;
    if(x->x_head_y > yr2)
      x->x_head_y = yr2;
    if(x->x_head_y < -yr2)
      x->x_head_y = -yr2;

    clock_delay(x->x_clock, 0.0f);
  }
}

static void xy_2_del_damp_phi_r_min(t_xy_2_del_damp_phi *x, t_float r_min)
{
  if(r_min < 0.1f)
    r_min = 0.1f;
  x->x_r_min = r_min;
  clock_delay(x->x_clock, 0.0f);
}

static void xy_2_del_damp_phi_sonic_speed(t_xy_2_del_damp_phi *x, t_float speed)
{
  if(speed < 10.0f)
    speed = 10.0f;
  if(speed > 2000.0f)
    speed = 2000.0f;
  x->x_speed = speed;
  clock_delay(x->x_clock, 0.0f);
}

static void xy_2_del_damp_phi_free(t_xy_2_del_damp_phi *x)
{
  clock_free(x->x_clock);
  
	freebytes(x->x_at, x->x_size_at * sizeof(t_atom));
  freebytes(x->x_rad, x->x_size_rad * sizeof(t_float));
}

static void *xy_2_del_damp_phi_new(t_symbol *s, int argc, t_atom *argv)
{
  t_xy_2_del_damp_phi *x = (t_xy_2_del_damp_phi *)pd_new(xy_2_del_damp_phi_class);
  
  x->x_room_x = 12.0f;
  x->x_room_y = 8.0f;
  x->x_head_x = 0.0f;
  x->x_head_y = 0.0f;
  x->x_src_x = 3.0f;
  x->x_src_y = 0.5f;
  x->x_r_min = 1.4f;
  x->x_speed = 340.0f;
  x->x_s_direct = gensym("direct");
  x->x_s_early1 = gensym("early1");
  x->x_s_early2 = gensym("early2");
  x->x_s_early3 = gensym("early3");
  x->x_s_early4 = gensym("early4");
  x->x_s_damp = gensym("damp");
  x->x_s_del = gensym("del");
  x->x_s_phi = gensym("phi");
  x->x_size_rad = 41; // 1 + 4 + 8 + 12 + 16
  x->x_size_at = 17; // 16 + 1
  x->x_rad = (t_float *)getbytes(x->x_size_rad * sizeof(t_float));
  x->x_at = (t_atom *)getbytes(x->x_size_at * sizeof(t_atom));
  outlet_new(&x->x_obj, &s_list);
  x->x_clock = clock_new(x, (t_method)xy_2_del_damp_phi_doit);
  x->x_180_over_pi  = (t_float)(180.0 / (4.0 * atan(1.0)));
  return (x);
}

void xy_2_del_damp_phi_setup(void)
{
  xy_2_del_damp_phi_class = class_new(gensym("xy_2_del_damp_phi"), (t_newmethod)xy_2_del_damp_phi_new, (t_method)xy_2_del_damp_phi_free,
    sizeof(t_xy_2_del_damp_phi), 0, A_GIMME, 0);
  class_addmethod(xy_2_del_damp_phi_class, (t_method)xy_2_del_damp_phi_src_xy, gensym("src_xy"), A_GIMME, 0);
  class_addmethod(xy_2_del_damp_phi_class, (t_method)xy_2_del_damp_phi_head_xy, gensym("head_xy"), A_GIMME, 0);
  class_addmethod(xy_2_del_damp_phi_class, (t_method)xy_2_del_damp_phi_room_xy, gensym("room_xy"), A_GIMME, 0);
  class_addmethod(xy_2_del_damp_phi_class, (t_method)xy_2_del_damp_phi_sonic_speed, gensym("sonic_speed"), A_FLOAT, 0);
  class_addmethod(xy_2_del_damp_phi_class, (t_method)xy_2_del_damp_phi_r_min, gensym("r_min"), A_FLOAT, 0);
}
