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_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; }