static void new_spread_dir(t_rvbap *x, t_float spreaddir[3], t_float vscartdir[3], t_float spread_base[3]) // subroutine for spreading { t_float beta,m_gamma; t_float a,b; t_float pi = 3.141592653589793; t_float power; m_gamma = acos(vscartdir[0] * spread_base[0] + vscartdir[1] * spread_base[1] + vscartdir[2] * spread_base[2])/pi*180; if(fabs(m_gamma) < 1){ angle_to_cart(x->x_azi+90, 0, spread_base); m_gamma = acos(vscartdir[0] * spread_base[0] + vscartdir[1] * spread_base[1] + vscartdir[2] * spread_base[2])/pi*180; } beta = 180 - m_gamma; b=sin(x->x_spread * pi / 180) / sin(beta * pi / 180); a=sin((180- x->x_spread - beta) * pi / 180) / sin (beta * pi / 180); spreaddir[0] = a * vscartdir[0] + b * spread_base[0]; spreaddir[1] = a * vscartdir[1] + b * spread_base[1]; spreaddir[2] = a * vscartdir[2] + b * spread_base[2]; power=sqrt(spreaddir[0]*spreaddir[0] + spreaddir[1]*spreaddir[1] + spreaddir[2]*spreaddir[2]); spreaddir[0] /= power; spreaddir[1] /= power; spreaddir[2] /= power; }
void vbap(double gains[MAX_CHANNELS], LS_DATA *ls_data, int azi, int ele) { /* calculates gain factors using loudspeaker setup and given direction */ double *cartdir; double power; int i,j,k; double small_g; double big_sm_g, gtmp[3]; int winner_triplet; int ls[3]; double g[3]; cartdir=angle_to_cart(azi,ele); big_sm_g = -100000.0; for(i=0;i<ls_data->triplet_amount;i++){ small_g = 10000000.0; for(j=0;j<ls_data->dimension;j++){ gtmp[j]=0.0; for(k=0;k<ls_data->dimension;k++) gtmp[j]+=cartdir[k]*ls_data->lsm[i][k+j*ls_data->dimension]; if(gtmp[j] < small_g){ small_g = gtmp[j]; } } if(small_g > big_sm_g){ big_sm_g = small_g; winner_triplet=i; g[0]=gtmp[0]; g[1]=gtmp[1]; ls[0]=ls_data->lstripl[i][0]; ls[1]=ls_data->lstripl[i][1]; if(ls_data->dimension==3){ g[2]=gtmp[2]; ls[2]=ls_data->lstripl[i][2]; } else { g[2]=0.0; ls[2]=1; } } } power=sqrt(g[0]*g[0] + g[1]*g[1] + g[2]*g[2]); g[0] /= power; g[1] /= power; g[2] /= power; for(i=0;i<MAX_CHANNELS;i++){ gains[i]=0.0; } gains[ls[0]-1]=g[0]; gains[ls[1]-1]=g[1]; if(ls_data->dimension==3){ gains[ls[2]-1]=g[2]; } free(cartdir); }
static void equal_reverb(t_rvbap *x, t_float *final_gs) // calculate constant reverb gains for equally distributed // reverb levels // this is achieved by calculating gains for a sound source // that is everywhere, i.e. present in all directions { t_float vscartdir[3]; t_float spreaddir[16][3]; t_float spreadbase[16][3]; long i, spreaddirnum; t_float power; if(x->x_dimension == 3){ spreaddirnum=5; // horizontal plane angle_to_cart(90, 0, spreaddir[0]); angle_to_cart(180, 0, spreaddir[1]); angle_to_cart(270, 0, spreaddir[2]); // above, below angle_to_cart(0, 90, spreaddir[3]); angle_to_cart(0, -90, spreaddir[4]); for(i=1;i<spreaddirnum;i++){ additive_vbap(x->x_reverb_gs,spreaddir[i],x); } } else if (x->x_dimension == 2) { // for 2-D we claculate virtual sources // every 45 degrees in a horizontal plane spreaddirnum=7; angle_to_cart(90, 0, spreaddir[0]); angle_to_cart(180, 0, spreaddir[1]); angle_to_cart(270, 0, spreaddir[2]); angle_to_cart(45, 0, spreaddir[3]); angle_to_cart(135, 0, spreaddir[4]); angle_to_cart(225, 0, spreaddir[5]); angle_to_cart(315, 0, spreaddir[6]); for(i=0;i<spreaddirnum;i++) additive_vbap(x->x_reverb_gs,spreaddir[i],x); } else return; for(i=0,power=0.0;i<x->x_ls_amount;i++){ power += x->x_reverb_gs[i] * x->x_reverb_gs[i]; } power = sqrt(power); for(i=0;i<x->x_ls_amount;i++){ final_gs[i] /= power; } }
static void spread_it(t_rvbap *x, t_float *final_gs) // apply the sound signal to multiple panning directions // that causes some spreading. // See theory in paper V. Pulkki "Uniform spreading of amplitude panned // virtual sources" in WASPAA 99 { t_float vscartdir[3]; t_float spreaddir[16][3]; t_float spreadbase[16][3]; long i, spreaddirnum; t_float power; if(x->x_dimension == 3){ spreaddirnum=16; angle_to_cart(x->x_azi,x->x_ele,vscartdir); new_spread_dir(x, spreaddir[0], vscartdir, x->x_spread_base); new_spread_base(x, spreaddir[0], vscartdir); cross_prod(x->x_spread_base, vscartdir, spreadbase[1]); // four orthogonal dirs cross_prod(spreadbase[1], vscartdir, spreadbase[2]); cross_prod(spreadbase[2], vscartdir, spreadbase[3]); // four between them for(i=0;i<3;i++) spreadbase[4][i] = (x->x_spread_base[i] + spreadbase[1][i]) / 2.0; for(i=0;i<3;i++) spreadbase[5][i] = (spreadbase[1][i] + spreadbase[2][i]) / 2.0; for(i=0;i<3;i++) spreadbase[6][i] = (spreadbase[2][i] + spreadbase[3][i]) / 2.0; for(i=0;i<3;i++) spreadbase[7][i] = (spreadbase[3][i] + x->x_spread_base[i]) / 2.0; // four at half spreadangle for(i=0;i<3;i++) spreadbase[8][i] = (vscartdir[i] + x->x_spread_base[i]) / 2.0; for(i=0;i<3;i++) spreadbase[9][i] = (vscartdir[i] + spreadbase[1][i]) / 2.0; for(i=0;i<3;i++) spreadbase[10][i] = (vscartdir[i] + spreadbase[2][i]) / 2.0; for(i=0;i<3;i++) spreadbase[11][i] = (vscartdir[i] + spreadbase[3][i]) / 2.0; // four at quarter spreadangle for(i=0;i<3;i++) spreadbase[12][i] = (vscartdir[i] + spreadbase[8][i]) / 2.0; for(i=0;i<3;i++) spreadbase[13][i] = (vscartdir[i] + spreadbase[9][i]) / 2.0; for(i=0;i<3;i++) spreadbase[14][i] = (vscartdir[i] + spreadbase[10][i]) / 2.0; for(i=0;i<3;i++) spreadbase[15][i] = (vscartdir[i] + spreadbase[11][i]) / 2.0; additive_vbap(final_gs,spreaddir[0],x); for(i=1;i<spreaddirnum;i++){ new_spread_dir(x, spreaddir[i], vscartdir, spreadbase[i]); additive_vbap(final_gs,spreaddir[i],x); } } else if (x->x_dimension == 2) { spreaddirnum=6; angle_to_cart(x->x_azi - x->x_spread, 0, spreaddir[0]); angle_to_cart(x->x_azi - x->x_spread/2, 0, spreaddir[1]); angle_to_cart(x->x_azi - x->x_spread/4, 0, spreaddir[2]); angle_to_cart(x->x_azi + x->x_spread/4, 0, spreaddir[3]); angle_to_cart(x->x_azi + x->x_spread/2, 0, spreaddir[4]); angle_to_cart(x->x_azi + x->x_spread, 0, spreaddir[5]); for(i=0;i<spreaddirnum;i++) additive_vbap(final_gs,spreaddir[i],x); } else return; if(x->x_spread > 70) for(i=0;i<x->x_ls_amount;i++){ final_gs[i] += (x->x_spread - 70) / 30.0 * (x->x_spread - 70) / 30.0 * 10.0; } for(i=0,power=0.0;i<x->x_ls_amount;i++){ power += final_gs[i] * final_gs[i]; } power = sqrt(power); for(i=0;i<x->x_ls_amount;i++){ final_gs[i] /= power; } }
static void vbap(t_float g[3], long ls[3], t_rvbap *x) { /* calculates gain factors using loudspeaker setup and given direction */ t_float power; int i,j,k, gains_modified; t_float small_g; t_float big_sm_g, gtmp[3]; long winner_set=0; t_float cartdir[3]; t_float new_cartdir[3]; t_float new_angle_dir[3]; long dim = x->x_dimension; long neg_g_am, best_neg_g_am; // transfering the azimuth angle to a decent value while(x->x_azi > 180) x->x_azi -= 360; while(x->x_azi < -179) x->x_azi += 360; // transferring the elevation to a decent value if(dim == 3){ while(x->x_ele > 180) x->x_ele -= 360; while(x->x_ele < -179) x->x_ele += 360; } else x->x_ele = 0; // go through all defined loudspeaker sets and find the set which // has all positive values. If such is not found, set with largest // minimum value is chosen. If at least one of gain factors of one LS set is negative // it means that the virtual source does not lie in that LS set. angle_to_cart(x->x_azi,x->x_ele,cartdir); big_sm_g = -100000.0; // initial value for largest minimum gain value best_neg_g_am=3; // how many negative values in this set for(i=0;i<x->x_lsset_amount;i++){ small_g = 10000000.0; neg_g_am = 3; for(j=0;j<dim;j++){ gtmp[j]=0.0; for(k=0;k<dim;k++) gtmp[j]+=cartdir[k]* x->x_set_inv_matx[i][k+j*dim]; if(gtmp[j] < small_g) small_g = gtmp[j]; if(gtmp[j]>= -0.01) neg_g_am--; } if(small_g > big_sm_g && neg_g_am <= best_neg_g_am){ big_sm_g = small_g; best_neg_g_am = neg_g_am; winner_set=i; g[0]=gtmp[0]; g[1]=gtmp[1]; ls[0]= x->x_lsset[i][0]; ls[1]= x->x_lsset[i][1]; if(dim==3){ g[2]=gtmp[2]; ls[2]= x->x_lsset[i][2]; } else { g[2]=0.0; ls[2]=0; } } } // If chosen set produced a negative value, make it zero and // calculate direction that corresponds to these new // gain values. This happens when the virtual source is outside of // all loudspeaker sets. if(dim==3){ gains_modified=0; for(i=0;i<dim;i++) if(g[i]<-0.01){ g[i]=0.0001; gains_modified=1; } if(gains_modified==1){ new_cartdir[0] = x->x_set_matx[winner_set][0] * g[0] + x->x_set_matx[winner_set][1] * g[1] + x->x_set_matx[winner_set][2] * g[2]; new_cartdir[1] = x->x_set_matx[winner_set][3] * g[0] + x->x_set_matx[winner_set][4] * g[1] + x->x_set_matx[winner_set][5] * g[2]; new_cartdir[2] = x->x_set_matx[winner_set][6] * g[0] + x->x_set_matx[winner_set][7] * g[1] + x->x_set_matx[winner_set][8] * g[2]; cart_to_angle(new_cartdir,new_angle_dir); x->x_azi = (long) (new_angle_dir[0] + 0.5); x->x_ele = (long) (new_angle_dir[1] + 0.5); } } power=sqrt(g[0]*g[0] + g[1]*g[1] + g[2]*g[2]); g[0] /= power; g[1] /= power; g[2] /= power; }
int vbap_zak_control(CSOUND *csound, VBAP_ZAK *p) { CART_VEC spreaddir[16]; CART_VEC spreadbase[16]; ANG_VEC atmp; int32 i,j, spreaddirnum; int n = p->n; MYFLT tmp_gains[MAXCHNLS],sum = FL(0.0); if (UNLIKELY(p->dim == 2 && fabs(*p->ele) > 0.0)) { csound->Warning(csound, Str("Warning: truncating elevation to 2-D plane\n")); *p->ele = FL(0.0); } if (*p->spread <FL(0.0)) *p->spread=FL(0.0); else if (*p->spread >FL(100.0)) *p->spread=FL(100.0); /* Current panning angles */ p->ang_dir.azi = (MYFLT) *p->azi; p->ang_dir.ele = (MYFLT) *p->ele; p->ang_dir.length = FL(1.0); angle_to_cart(p->ang_dir, &(p->cart_dir)); calc_vbap_gns(p->ls_set_am, p->dim, p->ls_sets, p->updated_gains, n, p->cart_dir); /* Calculated gain factors of a spreaded virtual source */ if (*p->spread > FL(0.0)) { if (p->dim == 3) { spreaddirnum=16; /* four orthogonal dirs */ new_spread_dir(&spreaddir[0], p->cart_dir, p->spread_base, *p->azi, *p->spread); new_spread_base(spreaddir[0], p->cart_dir,*p->spread, &p->spread_base); cross_prod(p->spread_base, p->cart_dir, &spreadbase[1]); cross_prod(spreadbase[1], p->cart_dir, &spreadbase[2]); cross_prod(spreadbase[2], p->cart_dir, &spreadbase[3]); /* four between them */ vec_mean(p->spread_base, spreadbase[1], &spreadbase[4]); vec_mean(spreadbase[1], spreadbase[2], &spreadbase[5]); vec_mean(spreadbase[2], spreadbase[3], &spreadbase[6]); vec_mean(spreadbase[3], p->spread_base, &spreadbase[7]); /* four at half spreadangle */ vec_mean(p->cart_dir, p->spread_base, &spreadbase[8]); vec_mean(p->cart_dir, spreadbase[1], &spreadbase[9]); vec_mean(p->cart_dir, spreadbase[2], &spreadbase[10]); vec_mean(p->cart_dir, spreadbase[3], &spreadbase[11]); /* four at quarter spreadangle */ vec_mean(p->cart_dir, spreadbase[8], &spreadbase[12]); vec_mean(p->cart_dir, spreadbase[9], &spreadbase[13]); vec_mean(p->cart_dir, spreadbase[10], &spreadbase[14]); vec_mean(p->cart_dir, spreadbase[11], &spreadbase[15]); for (i=1;i<spreaddirnum;i++) { new_spread_dir(&spreaddir[i], p->cart_dir, spreadbase[i],*p->azi,*p->spread); calc_vbap_gns(p->ls_set_am, p->dim, p->ls_sets, tmp_gains, n, spreaddir[i]); for (j=0;j<n;j++) { p->updated_gains[j] += tmp_gains[j]; } } } else if (p->dim == 2) { spreaddirnum = 6; atmp.ele = FL(0.0); atmp.azi = *p->azi - *p->spread; angle_to_cart(atmp, &spreaddir[0]); atmp.azi = *p->azi - *p->spread/2; angle_to_cart(atmp, &spreaddir[1]); atmp.azi = *p->azi - *p->spread/4; angle_to_cart(atmp, &spreaddir[2]); atmp.azi = *p->azi + *p->spread/4; angle_to_cart(atmp, &spreaddir[3]); atmp.azi = *p->azi + *p->spread/2; angle_to_cart(atmp, &spreaddir[4]); atmp.azi = *p->azi + *p->spread; angle_to_cart(atmp, &spreaddir[5]); for (i=0;i<spreaddirnum;i++) { calc_vbap_gns(p->ls_set_am, p->dim, p->ls_sets, tmp_gains, n, spreaddir[i]); for (j=0;j<n;j++) { p->updated_gains[j] += tmp_gains[j]; } } } } if (*p->spread > FL(70.0)) for (i=0;i<n ;i++) { p->updated_gains[i] +=(*p->spread - FL(70.0))/FL(30.0) * (*p->spread - FL(70.0))/FL(30.0)*FL(20.0); } /* normalization */ for (i=0;i<n;i++) { sum = sum+(p->updated_gains[i]*p->updated_gains[i]); } sum = SQRT(sum); for (i=0;i<n;i++) { p->updated_gains[i] /= sum; } return OK; }
int vbap_zak_moving_init(CSOUND *csound, VBAP_ZAK_MOVING *p) { int i, j, indx; MYFLT *ls_table, *ptr; LS_SET *ls_set_ptr; int n = p->n; p->n = (int)MYFLT2LONG(*p->numb); /* Set size */ /* Check to see this index is within the limits of za space. */ indx = (int32) *p->ndx; if (UNLIKELY(indx > csound->zalast)) { return csound->PerfError(csound, p->h.insdshead, Str("outz index > isizea. No output")); } else if (UNLIKELY(indx < 0)) { return csound->PerfError(csound, p->h.insdshead, Str("outz index < 0. No output.")); } /* Now read from the array in za space and write to the output. */ p->out_array = csound->zastart + (indx * CS_KSMPS);/* outputs */ csound->AuxAlloc(csound, p->n*sizeof(MYFLT)*4, &p->auxch); p->curr_gains = (MYFLT*)p->auxch.auxp; p->beg_gains = p->curr_gains + p->n; p->end_gains = p->beg_gains + p->n; p->updated_gains = p->end_gains + p->n; /* reading in loudspeaker info */ ls_table = (MYFLT*) (csound->QueryGlobalVariableNoCheck(csound, "vbap_ls_table_0")); p->dim = (int) ls_table[0]; p->ls_am = (int) ls_table[1]; p->ls_set_am = (int) ls_table[2]; ptr = &(ls_table[3]); csound->AuxAlloc(csound, p->ls_set_am * sizeof (LS_SET), &p->aux); if (UNLIKELY(p->aux.auxp == NULL)) { return csound->InitError(csound, Str("could not allocate memory")); } p->ls_sets = (LS_SET*) p->aux.auxp; ls_set_ptr = p->ls_sets; for (i=0 ; i < p->ls_set_am ; i++) { ls_set_ptr[i].ls_nos[2] = 0; /* initial setting */ for (j=0 ; j < p->dim ; j++) { ls_set_ptr[i].ls_nos[j] = (int) *(ptr++); } for (j=0 ; j < 9; j++) ls_set_ptr[i].ls_mx[j] = FL(0.0); /* initial setting */ for (j=0 ; j < (p->dim) * (p->dim); j++) { ls_set_ptr[i].ls_mx[j] = (MYFLT) *(ptr++); } } /* other initialization */ p->ele_vel = FL(1.0); /* functions specific to movement */ if (UNLIKELY(fabs(*p->field_am) < (2+ (p->dim - 2)*2))) { return csound->InitError(csound, Str("Have to have at least %d directions in vbapzmove"), 2 + (p->dim - 2) * 2); } if (p->dim == 2) p->point_change_interval = (int) (CS_EKR * *p->dur / (fabs(*p->field_am) - 1.0)); else if (LIKELY(p->dim == 3)) p->point_change_interval = (int) (CS_EKR * *p->dur / (fabs(*p->field_am) * 0.5 - 1.0)); else return csound->InitError(csound, Str("Wrong dimension")); p->point_change_counter = 0; p->curr_fld = 0; p->next_fld = 1; p->ang_dir.azi = *p->fld[0]; if (p->dim == 3) { p->ang_dir.ele = *p->fld[1]; } else { p->ang_dir.ele = FL(0.0); } if (p->dim == 3) { p->curr_fld = 1; p->next_fld = 2; } angle_to_cart(p->ang_dir, &(p->cart_dir)); p->spread_base.x = p->cart_dir.y; p->spread_base.y = p->cart_dir.z; p->spread_base.z = -p->cart_dir.x; vbap_zak_moving_control(csound,p); for (i=0;i<n;i++) { p->beg_gains[i] = p->updated_gains[i]; p->end_gains[i] = p->updated_gains[i]; } return OK; }
int vbap_zak_moving_control(CSOUND *csound, VBAP_ZAK_MOVING *p) { CART_VEC spreaddir[16]; CART_VEC spreadbase[16]; ANG_VEC atmp; int32 i,j, spreaddirnum; int n = p->n; CART_VEC tmp1, tmp2, tmp3; MYFLT coeff, angle; MYFLT tmp_gains[MAXCHNLS],sum = FL(0.0); /* Array long enough */ if (UNLIKELY(p->dim == 2 && fabs(p->ang_dir.ele) > 0.0)) { csound->Warning(csound, Str("Warning: truncating elevation to 2-D plane\n")); p->ang_dir.ele = FL(0.0); } if (*p->spread <FL(0.0)) *p->spread = FL(0.0); else if (*p->spread >FL(100.0)) *p->spread = FL(100.0); if (p->point_change_counter++ >= p->point_change_interval) { p->point_change_counter = 0; p->curr_fld = p->next_fld; if (++p->next_fld >= (int) fabs(*p->field_am)) { if (*p->field_am >= FL(0.0)) /* point-to-point */ p->next_fld = 0; else p->next_fld = 1; } if (p->dim == 3) { /* jumping over second field */ p->curr_fld = p->next_fld; if (++p->next_fld >= ((int) fabs(*p->field_am))) { if (*p->field_am >= FL(0.0)) /* point-to-point */ p->next_fld = 0; else p->next_fld = 1; } } if (UNLIKELY((p->fld[abs(p->next_fld)]==NULL))) return csound->PerfError(csound, p->h.insdshead, Str("Missing fields in vbapzmove\n")); if (*p->field_am >= FL(0.0) && p->dim == 2) /* point-to-point */ if (UNLIKELY(fabs(fabs(*p->fld[p->next_fld] - *p->fld[p->curr_fld]) - 180.0) < 1.0)) csound->Warning(csound, Str("Warning: Ambiguous transition 180 degrees.\n")); } if (*p->field_am >= FL(0.0)) { /* point-to-point */ if (p->dim == 3) { /* 3-D */ p->prev_ang_dir.azi = *p->fld[p->curr_fld-1]; p->next_ang_dir.azi = *p->fld[p->next_fld]; p->prev_ang_dir.ele = *p->fld[p->curr_fld]; p->next_ang_dir.ele = *p->fld[p->next_fld+1]; coeff = ((MYFLT) p->point_change_counter) / ((MYFLT) p->point_change_interval); angle_to_cart( p->prev_ang_dir,&tmp1); angle_to_cart( p->next_ang_dir,&tmp2); tmp3.x = (FL(1.0)-coeff) * tmp1.x + coeff * tmp2.x; tmp3.y = (FL(1.0)-coeff) * tmp1.y + coeff * tmp2.y; tmp3.z = (FL(1.0)-coeff) * tmp1.z + coeff * tmp2.z; coeff = (MYFLT)sqrt((double)(tmp3.x * tmp3.x + tmp3.y * tmp3.y + tmp3.z * tmp3.z)); tmp3.x /= coeff; tmp3.y /= coeff; tmp3.z /= coeff; cart_to_angle(tmp3,&(p->ang_dir)); } else if (p->dim == 2) { /* 2-D */ p->prev_ang_dir.azi = *p->fld[p->curr_fld]; p->next_ang_dir.azi = *p->fld[p->next_fld ]; p->prev_ang_dir.ele = p->next_ang_dir.ele = FL(0.0); scale_angles(&(p->prev_ang_dir)); scale_angles(&(p->next_ang_dir)); angle = (p->prev_ang_dir.azi - p->next_ang_dir.azi); while(angle > FL(180.0)) angle -= FL(360.0); while(angle < -FL(180.0)) angle += FL(360.0); coeff = ((MYFLT) p->point_change_counter) / ((MYFLT) p->point_change_interval); angle *= (coeff); p->ang_dir.azi = p->prev_ang_dir.azi - angle; p->ang_dir.ele = FL(0.0); } else { return csound->PerfError(csound, p->h.insdshead, Str("Missing fields in vbapzmove\n")); } } else { /* angular velocities */ if (p->dim == 2) { p->ang_dir.azi = p->ang_dir.azi + (*p->fld[p->next_fld] * CS_ONEDKR); scale_angles(&(p->ang_dir)); } else { /* 3D angular */ p->ang_dir.azi = p->ang_dir.azi + (*p->fld[p->next_fld] * CS_ONEDKR); p->ang_dir.ele = p->ang_dir.ele + p->ele_vel * (*p->fld[p->next_fld+1] * CS_ONEDKR); if (p->ang_dir.ele > FL(90.0)) { p->ang_dir.ele = FL(90.0); p->ele_vel = -p->ele_vel; } if (p->ang_dir.ele < FL(0.0)) { p->ang_dir.ele = FL(0.0); p->ele_vel = -p->ele_vel; } scale_angles(&(p->ang_dir)); } } angle_to_cart(p->ang_dir, &(p->cart_dir)); calc_vbap_gns(p->ls_set_am, p->dim, p->ls_sets, p->updated_gains, n, p->cart_dir); if (*p->spread > FL(0.0)) { if (p->dim == 3) { spreaddirnum=16; /* four orthogonal dirs */ new_spread_dir(&spreaddir[0], p->cart_dir, p->spread_base, p->ang_dir.azi, *p->spread); new_spread_base(spreaddir[0], p->cart_dir,*p->spread, &p->spread_base); cross_prod(p->spread_base, p->cart_dir, &spreadbase[1]); cross_prod(spreadbase[1], p->cart_dir, &spreadbase[2]); cross_prod(spreadbase[2], p->cart_dir, &spreadbase[3]); /* four between them */ vec_mean(p->spread_base, spreadbase[1], &spreadbase[4]); vec_mean(spreadbase[1], spreadbase[2], &spreadbase[5]); vec_mean(spreadbase[2], spreadbase[3], &spreadbase[6]); vec_mean(spreadbase[3], p->spread_base, &spreadbase[7]); /* four at half spreadangle */ vec_mean(p->cart_dir, p->spread_base, &spreadbase[8]); vec_mean(p->cart_dir, spreadbase[1], &spreadbase[9]); vec_mean(p->cart_dir, spreadbase[2], &spreadbase[10]); vec_mean(p->cart_dir, spreadbase[3], &spreadbase[11]); /* four at quarter spreadangle */ vec_mean(p->cart_dir, spreadbase[8], &spreadbase[12]); vec_mean(p->cart_dir, spreadbase[9], &spreadbase[13]); vec_mean(p->cart_dir, spreadbase[10], &spreadbase[14]); vec_mean(p->cart_dir, spreadbase[11], &spreadbase[15]); for (i=1;i<spreaddirnum;i++) { new_spread_dir(&spreaddir[i], p->cart_dir, spreadbase[i],p->ang_dir.azi,*p->spread); calc_vbap_gns(p->ls_set_am, p->dim, p->ls_sets, tmp_gains, n, spreaddir[i]); for (j=0;j<n;j++) { p->updated_gains[j] += tmp_gains[j]; } } } else if (p->dim == 2) { spreaddirnum=6; atmp.ele=FL(0.0); atmp.azi=p->ang_dir.azi - *p->spread; angle_to_cart(atmp, &spreaddir[0]); atmp.azi=p->ang_dir.azi - *p->spread/2; angle_to_cart(atmp, &spreaddir[1]); atmp.azi=p->ang_dir.azi - *p->spread/4; angle_to_cart(atmp, &spreaddir[2]); atmp.azi=p->ang_dir.azi + *p->spread/4; angle_to_cart(atmp, &spreaddir[3]); atmp.azi=p->ang_dir.azi + *p->spread/2; angle_to_cart(atmp, &spreaddir[4]); atmp.azi=p->ang_dir.azi + *p->spread; angle_to_cart(atmp, &spreaddir[5]); for (i=0;i<spreaddirnum;i++) { calc_vbap_gns(p->ls_set_am, p->dim, p->ls_sets, tmp_gains, n, spreaddir[i]); for (j=0;j<n;j++) { p->updated_gains[j] += tmp_gains[j]; } } } } if (*p->spread > FL(70.0)) for (i=0;i<n ;i++) { p->updated_gains[i] += (*p->spread - FL(70.0))/FL(30.0) * (*p->spread - FL(70.0))/FL(30.0)*FL(10.0); } /* normalization */ for (i=0;i<n;i++) { sum += (p->updated_gains[i]*p->updated_gains[i]); } sum = SQRT(sum); for (i=0;i<n;i++) { p->updated_gains[i] /= sum; } return OK; }
int vbap_zak_init(CSOUND *csound, VBAP_ZAK *p) { /* Initializations before run time */ int i, j, indx; MYFLT *ls_table, *ptr; /* , *gains; */ LS_SET *ls_set_ptr; int n = p->n = (int)MYFLT2LONG(*p->numb); /* Set size */ char name[24]; /* Check to see this index is within the limits of za space. */ indx = (int32) *p->ndx; if (UNLIKELY(indx > csound->zalast)) { return csound->PerfError(csound, p->h.insdshead, Str("outz index > isizea. No output")); } else if (UNLIKELY(indx < 0)) { return csound->PerfError(csound, p->h.insdshead, Str("outz index < 0. No output.")); } if ((int)*p->layout==0) strcpy(name, "vbap_ls_table"); else snprintf(name, 24, "vbap_ls_table_%d", (int)*p->layout==0); /* Now read from the array in za space and write to the output. */ p->out_array = csound->zastart + (indx * CS_KSMPS);/* outputs */ csound->AuxAlloc(csound, p->n*sizeof(MYFLT)*4, &p->auxch); p->curr_gains = (MYFLT*)p->auxch.auxp; p->beg_gains = p->curr_gains + p->n; p->end_gains = p->beg_gains + p->n; p->updated_gains = p->end_gains + p->n; ls_table = (MYFLT*) (csound->QueryGlobalVariableNoCheck(csound, name)); p->dim = (int) ls_table[0]; /* reading in loudspeaker info */ p->ls_am = (int) ls_table[1]; p->ls_set_am = (int) ls_table[2]; ptr = &(ls_table[3]); csound->AuxAlloc(csound, p->ls_set_am * sizeof (LS_SET), &p->aux); if (UNLIKELY(p->aux.auxp == NULL)) { return csound->InitError(csound, Str("could not allocate memory")); } p->ls_sets = (LS_SET*) p->aux.auxp; ls_set_ptr = p->ls_sets; for (i=0 ; i < p->ls_set_am ; i++) { ls_set_ptr[i].ls_nos[2] = 0; /* initial setting */ for (j=0 ; j < p->dim ; j++) { ls_set_ptr[i].ls_nos[j] = (int) *(ptr++); } for (j=0 ; j < 9; j++) ls_set_ptr[i].ls_mx[j] = FL(0.0); /* initial setting */ for (j=0 ; j < (p->dim) * (p->dim); j++) { ls_set_ptr[i].ls_mx[j] = (MYFLT) *(ptr++); } } /* other initialization */ if (UNLIKELY(p->dim == 2 && fabs(*p->ele) > 0.0)) { csound->Warning(csound, Str("Warning: truncating elevation to 2-D plane\n")); *p->ele = FL(0.0); } p->ang_dir.azi = (MYFLT) *p->azi; p->ang_dir.ele = (MYFLT) *p->ele; p->ang_dir.length = FL(1.0); angle_to_cart(p->ang_dir, &(p->cart_dir)); p->spread_base.x = p->cart_dir.y; p->spread_base.y = p->cart_dir.z; p->spread_base.z = -p->cart_dir.x; vbap_zak_control(csound,p); for (i=0;i<n;i++) { p->beg_gains[i] = p->updated_gains[i]; p->end_gains[i] = p->updated_gains[i]; } return OK; }