diff --git a/libtascar/include/fdn.h b/libtascar/include/fdn.h index 56ea9925..0a3b7a26 100644 --- a/libtascar/include/fdn.h +++ b/libtascar/include/fdn.h @@ -185,7 +185,7 @@ namespace TASCAR { public: enum gainmethod_t { original, mean, schroeder }; fdn_t(uint32_t fdnorder, uint32_t maxdelay, bool logdelays, gainmethod_t gm, - bool feedback_); + bool feedback_, std::vector rallpass); ~fdn_t(){}; void set_logdelays(bool ld) { logdelays_ = ld; }; inline void process(std::vector& src, bool use_biquad) @@ -196,8 +196,8 @@ namespace TASCAR { // rotation: for(auto& path : fdnpath) { foa_sample_t tmp(path.delayline[path.pos]); - path.reflection.filter(tmp, use_biquad); path.rotation.rotate(tmp); + path.reflection.filter(tmp, use_biquad); path.dlout = tmp; outval += tmp; } @@ -247,8 +247,8 @@ namespace TASCAR { // rotation: for(auto& path : fdnpath) { foa_sample_t tmp(path.delayline[path.pos]); - path.reflection.filter(tmp, use_biquad); path.rotation.rotate(tmp); + path.reflection.filter(tmp, use_biquad); path.dlout = tmp; outval += tmp; } @@ -279,6 +279,8 @@ namespace TASCAR { reflectionfilter_t prefilt1; // FDN path: std::vector fdnpath; + // allpass filter radius, requires four entries: + std::vector rallpass; }; } // namespace TASCAR diff --git a/libtascar/src/acousticmodel.cc b/libtascar/src/acousticmodel.cc index 4400d0e4..f40a18c2 100644 --- a/libtascar/src/acousticmodel.cc +++ b/libtascar/src/acousticmodel.cc @@ -260,8 +260,8 @@ uint32_t acoustic_model_t::process(const TASCAR::transport_t& tp) return 1; } } // of visible - } // of layers check - } // of ISM order check + } // of layers check + } // of ISM order check } else { delayline.add_chunk(audio); } @@ -631,8 +631,9 @@ void receiver_t::configure() scatter_handle = create_diffuse_state_data(f_sample, n_fragment); scatterfilterpath.resize(scatterreflections); if(scatterreflections > 0) { - scatterfilter = new TASCAR::fdn_t(scatterreflections, (uint32_t)f_sample, - true, TASCAR::fdn_t::mean, false); + scatterfilter = + new TASCAR::fdn_t(scatterreflections, (uint32_t)f_sample, true, + TASCAR::fdn_t::mean, false, {0.0f, 0.0f, 0.0f, 0.0f}); scatterfilter->set_scatterpar( scatterspread, f_sample * (0.1f * scatterstructuresize / 340.0f), f_sample * (scatterstructuresize / 340.0f), f_sample, @@ -750,7 +751,7 @@ void receiver_t::postproc(std::vector& output) // path.dlout = x; ++kflt; } - scatterfilter->process(scatterfilterpath,false); + scatterfilter->process(scatterfilterpath, false); scatterbuffer->w()[k] = scatterfilter->outval.w; scatterbuffer->x()[k] = scatterfilter->outval.x; scatterbuffer->y()[k] = scatterfilter->outval.y; diff --git a/libtascar/src/fdn.cc b/libtascar/src/fdn.cc index 2bd1e07c..1d266f24 100644 --- a/libtascar/src/fdn.cc +++ b/libtascar/src/fdn.cc @@ -36,14 +36,20 @@ void fdnpath_t::init(uint32_t maxdelay) }; fdn_t::fdn_t(uint32_t fdnorder, uint32_t maxdelay, bool logdelays, - gainmethod_t gm, bool feedback_) + gainmethod_t gm, bool feedback_, std::vector rallpass_) : logdelays_(logdelays), fdnorder_(fdnorder), maxdelay_(maxdelay), - feedbackmat(fdnorder_ * fdnorder_), gainmethod(gm), feedback(feedback_) + feedbackmat(fdnorder_ * fdnorder_), gainmethod(gm), feedback(feedback_), + rallpass(rallpass_) { + if(rallpass.size() != 4u) + throw TASCAR::ErrMsg( + "Allpass filter radius vector requires four entries, received " + + std::to_string(rallpass.size())); for(auto& v : feedbackmat) v = 0.0f; prefilt0.set_allpass(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f); - prefilt1.set_allpass(0.87f, 0.87f, 0.87f, 0.87f, 0.87f, 0.25f * TASCAR_PIf); + prefilt1.set_allpass(0.87f, rallpass[0], rallpass[1], rallpass[2], + rallpass[3], 0.25f * TASCAR_PIf); fdnpath.resize(fdnorder); for(size_t k = 0; k < fdnpath.size(); ++k) { fdnpath[k].init(maxdelay); @@ -85,8 +91,8 @@ void fdn_t::setpar_t60(float az, float daz, float t_min, float t_max, float t60, uint32_t d((uint32_t)std::max(0.0f, t_)); fdnpath[tap].delay = std::max(2u, std::min(maxdelay_ - 1u, d)); fdnpath[tap].reflection.set_allpass( - 0.87f * (float)tap / ((float)fdnorder_ - 1.0f), 0.87f, 0.88f, 0.89f, - 0.9f, + 0.87f * (float)tap / ((float)fdnorder_ - 1.0f), rallpass[0], + rallpass[1], rallpass[2], rallpass[3], TASCAR_PIf * (0.001f + 0.25f * (float)tap / ((float)fdnorder_ - 1.0f))); // eta[k] = 0.87f * (float)k / ((float)d1 - 1.0f); t_mean += (float)(fdnpath[tap].delay); @@ -182,10 +188,9 @@ void fdn_t::set_scatterpar(float daz, float t_min, float t_max, float t60, uint32_t d((uint32_t)std::max(0.0f, t_)); fdnpath[tap].delay = std::max(2u, std::min(maxdelay_ - 1u, d)); fdnpath[tap].reflection.set_allpass( - 0.87f * (float)tap / ((float)fdnorder_ - 1.0f), 0.87f, 0.88f, 0.89f, - 0.9f, + 0.87f * (float)tap / ((float)fdnorder_ - 1.0f), rallpass[0], + rallpass[1], rallpass[2], rallpass[3], TASCAR_PIf * (0.001f + 0.25f * (float)tap / ((float)fdnorder_ - 1.0f))); - // eta[k] = 0.87f * (float)k / ((float)d1 - 1.0f); t_mean += (float)(fdnpath[tap].delay); } // if feed forward model, then truncate delays: diff --git a/plugins/src/receivermod_simplefdn.cc b/plugins/src/receivermod_simplefdn.cc index b3b0071a..92426c0a 100644 --- a/plugins/src/receivermod_simplefdn.cc +++ b/plugins/src/receivermod_simplefdn.cc @@ -56,6 +56,7 @@ class simplefdn_vars_t : public TASCAR::receivermod_base_t { bool use_lowcut = false; bool truncate_forward = false; bool use_biquad_allpass = false; + std::vector rallpass = {0.96f, 0.95f, 0.951f, 0.93f}; }; simplefdn_vars_t::simplefdn_vars_t(tsccfg::node_t xmlsrc) @@ -101,6 +102,12 @@ simplefdn_vars_t::simplefdn_vars_t(tsccfg::node_t xmlsrc) GET_ATTRIBUTE_BOOL( use_biquad_allpass, "Use biquad allpass filters instead of first order filters"); + GET_ATTRIBUTE(rallpass, "[0,1]", + "Allpass filter radius vector (requires four entries)"); + if(rallpass.size() != 4u) + throw TASCAR::ErrMsg( + "Allpass filter radius vector requires four entries, received " + + std::to_string(rallpass.size())); } simplefdn_vars_t::~simplefdn_vars_t() {} @@ -264,14 +271,14 @@ void simplefdn_t::configure() if(feedback_delay_network) delete feedback_delay_network; srcpath.resize(fdnorder); - feedback_delay_network = - new TASCAR::fdn_t(fdnorder, (uint32_t)f_sample, logdelays, gm, true); + feedback_delay_network = new TASCAR::fdn_t(fdnorder, (uint32_t)f_sample, + logdelays, gm, true, rallpass); for(auto& pff : feedforward_delay_network) delete pff; feedforward_delay_network.clear(); for(uint32_t k = 0; k < forwardstages; ++k) - feedforward_delay_network.push_back( - new TASCAR::fdn_t(fdnorder, (uint32_t)f_sample, logdelays, gm, false)); + feedforward_delay_network.push_back(new TASCAR::fdn_t( + fdnorder, (uint32_t)f_sample, logdelays, gm, false, rallpass)); if(foa_out) delete foa_out; foa_out = new TASCAR::amb1wave_t(n_fragment); diff --git a/test/Makefile b/test/Makefile index be5baf43..dee9002a 100644 --- a/test/Makefile +++ b/test/Makefile @@ -1,50 +1,56 @@ -TESTS = test_snd_pink_diffuse test_ir1 test_ir2 test_ir3 test_ir4 \ - test_ir_proxy_air test_ir_proxy_gain test_ir_proxy_delay \ - test_ir_proxy_direction test_ir6_ismminmax test_snd1 \ - test_snd_include_sound test_snd2 test_snd4 test_snd3 test_snd5 \ - test_pos1 test_pos2 test_pos_trackinterp test_snd_door1 \ - test_snd_door2 test_snd_door3 test_pos_door test_snd_layers \ - test_snd_rec_amb1h1v test_wav_diffuse test_wav_diffuse_hoa2d \ - test_ir_hoa2d_offset test_wav_diffuse_nsp4 test_wav_diffuse_hoa2d4 \ - test_wav_diffuse_layerbug test_wav_diffirs test_sndgainramp \ - test_sndgainramp2 test_ir_spkcorr test_snd_calib1 test_snd_calib2 \ - test_snd_vbap51 test_snd_pink test_snd_sndfile test_snd_sndfile2 \ - test_snd_door4 test_snd_roommic test_level_vbap3d test_ir_ortf_0deg \ - test_ir_ortf_55deg test_ir_scatter test_ir_noscatter \ - test_ir_scatter_ortf test_snd_sourcedir_generic \ - test_snd_sourcedir_generic1 test_snd_sourcedir_generic_cardioid \ - test_ir_wfs test_ir_wfs_noplanewave test_level_hoa2d_basic \ - test_level_hoa2d_maxre test_ir_reverb test_ir_simplefdn \ - test_ir_simplefdn_gain test_ir_simplefdn_feedforward \ - test_snd_vbap3d_speakermatch test_ir_volumetric test_pos_obstacle \ - test_pos_obstacle_inner test_level_absorption test_ir_hrtf_0deg \ - test_ir_hrtf_45deg test_ir_hrtf_75deg test_ir_hrtf_90deg \ - test_ir_hrtf_105deg test_ir_hrtf_135deg test_ir_hrtf_180deg \ - test_ir_hrtf_225deg test_ir_hrtf_270deg test_ir_hrtf_315deg \ - test_ir_hrtf_el90deg test_ir_hrtf_el-90deg test_ir_hrtf_el45deg \ - test_ir_hrtf_el-45deg test_ir_hrtf_diffuse1 test_ir_hrtf_diffuse2 \ - test_ir_delay test_ir_delay2 test_ir_delay3 test_snd_reverb \ - test_wav_multichannel test_snd_zeros test_ir_sub test_ir_sub_hoa2d \ - test_ir_sub_nsp test_ir_partconvrev test_ir_partconvrev_offset \ - test_ir_micarray_az0deg test_ir_micarray_az45deg \ - test_ir_micarray_az75deg test_ir_micarray_az90deg \ - test_ir_micarray_az105deg test_ir_micarray_az135deg \ - test_ir_micarray_az180deg test_ir_micarray_az225deg \ - test_ir_micarray_az270deg test_ir_micarray_az315deg \ - test_ir_micarray_el45deg test_ir_micarray_el90deg \ - test_ir_micarray_el-45deg test_ir_micarray_el-90deg \ - test_snd_diffuse_micarray test_snd_micarray_az0deg \ - test_ir_micarraysinc test_ir_amb1 test_ir_amb1_y test_ir_amb1_z \ - test_snd_diffuse_0deg test_snd_diffuse_17deg \ - test_snd_diffuse_rec17deg test_snd_maskplugin_fig8 \ - test_snd_maskplugin_multibeam test_snd_maskplugin_multibeam1 \ - test_snd_maskplugin_sampledgain test_snd_diffuse_inphase \ - test_snd_diffuse_basic test_snd_diffuse_maxre \ - test_snd_maskplugin_multibeam_diff test_ir_apfilter_highpass \ - test_ir_apfilter_lowpass test_snd_hoa2d_fuma_hos \ - test_ir_material_carpet test_ir_material_window test_ir1_spkcalib \ - test_snd_spkcorr0 test_snd_spkcorr70 test_snd_nospkcorr \ - test_snd_spkcorr_long test_ir_nodelaylineimagesource +TESTS = test_snd_pink_diffuse test_ir1 test_ir2 test_ir3 test_ir4 \ + test_ir_proxy_air test_ir_proxy_gain test_ir_proxy_delay \ + test_ir_proxy_direction test_ir6_ismminmax test_snd1 \ + test_snd_include_sound test_snd2 test_snd4 test_snd3 \ + test_snd5 test_pos1 test_pos2 test_pos_trackinterp \ + test_snd_door1 test_snd_door2 test_snd_door3 test_pos_door \ + test_snd_layers test_snd_rec_amb1h1v test_wav_diffuse \ + test_wav_diffuse_hoa2d test_ir_hoa2d_offset \ + test_wav_diffuse_nsp4 test_wav_diffuse_hoa2d4 \ + test_wav_diffuse_layerbug test_wav_diffirs test_sndgainramp \ + test_sndgainramp2 test_ir_spkcorr test_snd_calib1 \ + test_snd_calib2 test_snd_vbap51 test_snd_pink \ + test_snd_sndfile test_snd_sndfile2 test_snd_door4 \ + test_snd_roommic test_level_vbap3d test_ir_ortf_0deg \ + test_ir_ortf_55deg test_ir_scatter test_ir_noscatter \ + test_ir_scatter_ortf test_snd_sourcedir_generic \ + test_snd_sourcedir_generic1 \ + test_snd_sourcedir_generic_cardioid test_ir_wfs \ + test_ir_wfs_noplanewave test_level_hoa2d_basic \ + test_level_hoa2d_maxre test_ir_reverb test_ir_simplefdn \ + test_ir_simplefdn_biquadallpass test_ir_simplefdn_gain \ + test_ir_simplefdn_feedforward test_snd_vbap3d_speakermatch \ + test_ir_volumetric test_pos_obstacle test_pos_obstacle_inner \ + test_level_absorption test_ir_hrtf_0deg test_ir_hrtf_45deg \ + test_ir_hrtf_75deg test_ir_hrtf_90deg test_ir_hrtf_105deg \ + test_ir_hrtf_135deg test_ir_hrtf_180deg test_ir_hrtf_225deg \ + test_ir_hrtf_270deg test_ir_hrtf_315deg test_ir_hrtf_el90deg \ + test_ir_hrtf_el-90deg test_ir_hrtf_el45deg \ + test_ir_hrtf_el-45deg test_ir_hrtf_diffuse1 \ + test_ir_hrtf_diffuse2 test_ir_delay test_ir_delay2 \ + test_ir_delay3 test_snd_reverb test_wav_multichannel \ + test_snd_zeros test_ir_sub test_ir_sub_hoa2d test_ir_sub_nsp \ + test_ir_partconvrev test_ir_partconvrev_offset \ + test_ir_micarray_az0deg test_ir_micarray_az45deg \ + test_ir_micarray_az75deg test_ir_micarray_az90deg \ + test_ir_micarray_az105deg test_ir_micarray_az135deg \ + test_ir_micarray_az180deg test_ir_micarray_az225deg \ + test_ir_micarray_az270deg test_ir_micarray_az315deg \ + test_ir_micarray_el45deg test_ir_micarray_el90deg \ + test_ir_micarray_el-45deg test_ir_micarray_el-90deg \ + test_snd_diffuse_micarray test_snd_micarray_az0deg \ + test_ir_micarraysinc test_ir_amb1 test_ir_amb1_y \ + test_ir_amb1_z test_snd_diffuse_0deg test_snd_diffuse_17deg \ + test_snd_diffuse_rec17deg test_snd_maskplugin_fig8 \ + test_snd_maskplugin_multibeam test_snd_maskplugin_multibeam1 \ + test_snd_maskplugin_sampledgain test_snd_diffuse_inphase \ + test_snd_diffuse_basic test_snd_diffuse_maxre \ + test_snd_maskplugin_multibeam_diff test_ir_apfilter_highpass \ + test_ir_apfilter_lowpass test_snd_hoa2d_fuma_hos \ + test_ir_material_carpet test_ir_material_window \ + test_ir1_spkcalib test_snd_spkcorr0 test_snd_spkcorr70 \ + test_snd_nospkcorr test_snd_spkcorr_long \ + test_ir_nodelaylineimagesource #test_ir_simplefdn_optimt60 #test_ir_scatter_reflections diff --git a/test/expected_ir_simplefdn_biquadallpass.wav b/test/expected_ir_simplefdn_biquadallpass.wav new file mode 100644 index 00000000..65c8f571 Binary files /dev/null and b/test/expected_ir_simplefdn_biquadallpass.wav differ diff --git a/test/test_ir_simplefdn_biquadallpass.tsc b/test/test_ir_simplefdn_biquadallpass.tsc new file mode 100644 index 00000000..030c3835 --- /dev/null +++ b/test/test_ir_simplefdn_biquadallpass.tsc @@ -0,0 +1,9 @@ + + + + + + + + +