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