Skip to content

Commit 10845b8

Browse files
committed
Add new features and bug fixes
Added ‘Anechoic Chamber’ option to acoustic spaces to allow for removal of reverberation Added ‘Max output length’ option in advanced settings which can be used to force trim/crop the outputs Updated acoustic space import tool with more parameters allowing finer control of the spatial transformation. Fixed a bug in the acoustic space import tool impacting time domain alignment accuracy Added new acoustic spaces including the rooms from ASH Listening Set Added new parameters in advanced settings for calibration control Added option in advanced settings to clear the cache files including downloaded acoustic spaces and HRTF related data
1 parent 85dff4f commit 10845b8

8 files changed

Lines changed: 1588 additions & 1570 deletions

File tree

ash_toolset/__main__.py

Lines changed: 291 additions & 158 deletions
Large diffs are not rendered by default.

ash_toolset/air_processing.py

Lines changed: 703 additions & 800 deletions
Large diffs are not rendered by default.

ash_toolset/brir_generation.py

Lines changed: 89 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,10 @@ def generate_integrated_brir(brir_name, spatial_res=1, report_progress=0, gui_l
7979
hrtf_direction_misalign_comp = brir_meta_dict.get("hrtf_direction_misalign_comp")
8080
hrtf_df_cal_mode = brir_meta_dict.get("hrtf_df_cal_mode")
8181
reverb_tail_crop_db = brir_meta_dict.get("reverb_tail_crop_db")
82+
brir_df_cal_mode = brir_meta_dict.get("brir_df_cal_mode")
83+
brir_max_length=brir_meta_dict.get("brir_max_length")
84+
octave_smoothing_n=brir_meta_dict.get("octave_smoothing_n")
85+
brir_df_cal_factor=brir_meta_dict.get("brir_df_cal_factor")
8286
else:
8387
raise ValueError('brir_meta_dict not populated')
8488

@@ -215,6 +219,12 @@ def generate_integrated_brir(brir_name, spatial_res=1, report_progress=0, gui_l
215219
needs_update = True
216220

217221
if needs_update:
222+
log_string = 'Downloading updates'
223+
hf.log_with_timestamp(log_string, gui_logger)
224+
if report_progress > 0:
225+
progress = 1/100
226+
hf.update_gui_progress(report_progress=report_progress, progress=progress, message=log_string)
227+
218228
air_processing.acoustic_space_updates(download_updates=True, gui_logger=gui_logger)
219229
except Exception as e:
220230
hf.log_with_timestamp(f"Failed to check/update acoustic spaces: {e}", gui_logger)
@@ -347,9 +357,7 @@ def generate_integrated_brir(brir_name, spatial_res=1, report_progress=0, gui_l
347357
total_azim_hrir = len(hrir_selected[0])
348358
total_chan_hrir = len(hrir_selected[0][0])
349359
total_samples_hrir = len(hrir_selected[0][0][0])
350-
base_elev_idx = total_elev_hrir//2
351-
352-
360+
353361
############################## DF calibration CTF loading
354362
#
355363
ctf_mag_db = None # main CTF magnitude in dB
@@ -538,50 +546,51 @@ def generate_integrated_brir(brir_name, spatial_res=1, report_progress=0, gui_l
538546

539547

540548
# grab reverberant BRIRs from interim matrix and place in output matrix
541-
for elev in range(total_elev_hrir):
542-
for azim in range(total_azim_hrir):
543-
azim_deg = int(azim*azim_nearest)
544-
#case for minimal set (7 directions)
545-
if total_azim_reverb == 7:
546-
if azim_deg < 15 or azim_deg > 345:
547-
brir_azim_ind=0
548-
elif azim_deg < 60:
549-
brir_azim_ind=1
550-
elif azim_deg < 120:
551-
brir_azim_ind=2
552-
elif azim_deg < 180:
553-
brir_azim_ind=3
554-
elif azim_deg <= 240:
555-
brir_azim_ind=4
556-
elif azim_deg <= 300:
557-
brir_azim_ind=5
558-
else:
559-
brir_azim_ind=6
560-
#case for minimal set (5 directions)
561-
elif total_azim_reverb == 5:
562-
if azim_deg < 15 or azim_deg > 345:
563-
brir_azim_ind=0
564-
elif azim_deg < 120:
565-
brir_azim_ind=1
566-
elif azim_deg < 180:
567-
brir_azim_ind=2
568-
elif azim_deg <= 240:
569-
brir_azim_ind=3
549+
if meas_rt60 > 0:
550+
for elev in range(total_elev_hrir):
551+
for azim in range(total_azim_hrir):
552+
azim_deg = int(azim*azim_nearest)
553+
#case for minimal set (7 directions)
554+
if total_azim_reverb == 7:
555+
if azim_deg < 15 or azim_deg > 345:
556+
brir_azim_ind=0
557+
elif azim_deg < 60:
558+
brir_azim_ind=1
559+
elif azim_deg < 120:
560+
brir_azim_ind=2
561+
elif azim_deg < 180:
562+
brir_azim_ind=3
563+
elif azim_deg <= 240:
564+
brir_azim_ind=4
565+
elif azim_deg <= 300:
566+
brir_azim_ind=5
567+
else:
568+
brir_azim_ind=6
569+
#case for minimal set (5 directions)
570+
elif total_azim_reverb == 5:
571+
if azim_deg < 15 or azim_deg > 345:
572+
brir_azim_ind=0
573+
elif azim_deg < 120:
574+
brir_azim_ind=1
575+
elif azim_deg < 180:
576+
brir_azim_ind=2
577+
elif azim_deg <= 240:
578+
brir_azim_ind=3
579+
else:
580+
brir_azim_ind=4
581+
#case for multiple directions on horizontal plane, every x deg azimuth
582+
elif total_azim_reverb > 0:
583+
#map hrir azimuth to appropriate brir azimuth
584+
#round azim to nearest X deg and get new ID
585+
brir_azim = hf.round_to_multiple(azim_deg,nearest_azim_reverb)#brir_reverberation is nearest X deg, variable
586+
if brir_azim >= 360:
587+
brir_azim = 0
588+
brir_azim_ind = int(brir_azim/nearest_azim_reverb)#get index
570589
else:
571-
brir_azim_ind=4
572-
#case for multiple directions on horizontal plane, every x deg azimuth
573-
elif total_azim_reverb > 0:
574-
#map hrir azimuth to appropriate brir azimuth
575-
#round azim to nearest X deg and get new ID
576-
brir_azim = hf.round_to_multiple(azim_deg,nearest_azim_reverb)#brir_reverberation is nearest X deg, variable
577-
if brir_azim >= 360:
578-
brir_azim = 0
579-
brir_azim_ind = int(brir_azim/nearest_azim_reverb)#get index
580-
else:
581-
raise ValueError('Unable to process BRIR reverberation data. Invalid number of reverberation sources: ' + str(total_azim_reverb) )
582-
583-
for chan in range(CN.TOTAL_CHAN_BRIR):
584-
brir_out[elev][azim][chan][0:n_fft] = np.copy(brir_reverberation[0][brir_azim_ind][chan][0:n_fft])
590+
raise ValueError('Unable to process BRIR reverberation data. Invalid number of reverberation sources: ' + str(total_azim_reverb) )
591+
592+
for chan in range(CN.TOTAL_CHAN_BRIR):
593+
brir_out[elev][azim][chan][0:n_fft] = np.copy(brir_reverberation[0][brir_azim_ind][chan][0:n_fft])
585594

586595

587596

@@ -709,9 +718,9 @@ def generate_integrated_brir(brir_name, spatial_res=1, report_progress=0, gui_l
709718
#convert to mag
710719
brir_fft_avg_mag = hf.db2mag(brir_fft_avg_db)
711720
#level ends of spectrum
712-
brir_fft_avg_mag_sm = hf.level_spectrum_ends(brir_fft_avg_mag, 15, 18500, smooth_win = 5, n_fft=CN.N_FFT)#40, 19000, smooth_win = 7
721+
brir_fft_avg_mag_sm = hf.level_spectrum_ends(brir_fft_avg_mag, 15, 18500, smooth_win = octave_smoothing_n, n_fft=CN.N_FFT)#40, 19000, smooth_win = 7
713722
#octave smoothing
714-
brir_fft_avg_mag_sm = hf.smooth_gaussian_octave(data=brir_fft_avg_mag_sm, n_fft=CN.N_FFT, fraction=6)
723+
brir_fft_avg_mag_sm = hf.smooth_gaussian_octave(data=brir_fft_avg_mag_sm, n_fft=CN.N_FFT, fraction=octave_smoothing_n)
715724

716725
#include CTF if DF calibration reversal is enabled
717726
if ctf_adj_loaded and ctf_adj_mag_db is not None:
@@ -720,8 +729,9 @@ def generate_integrated_brir(brir_name, spatial_res=1, report_progress=0, gui_l
720729
hf.log_with_timestamp("HRTF CTF Adjustment response available, applying to integrated response CTF.")
721730

722731

723-
#invert response
724-
brir_fft_avg_mag_inv = hf.db2mag(hf.mag2db(brir_fft_avg_mag_sm)*-1)
732+
#invert response and scale by user selected strength factor
733+
brir_df_cal_factor=max(0.05,brir_df_cal_factor)
734+
brir_fft_avg_mag_inv = hf.db2mag(hf.mag2db(brir_fft_avg_mag_sm)*-1*brir_df_cal_factor)
725735

726736
#include CTF if DF calibration reversal is enabled
727737
if df_cal_reversal:
@@ -732,7 +742,19 @@ def generate_integrated_brir(brir_name, spatial_res=1, report_progress=0, gui_l
732742
hf.log_with_timestamp("HRTF CTF DF response not available, skipping HRTF DF reintegration.", gui_logger)
733743

734744
#create min phase FIR
735-
brir_df_inv_fir = hf.build_min_phase_filter(smoothed_mag=brir_fft_avg_mag_inv, truncate_len=4096, n_fft=CN.N_FFT)#2048
745+
if brir_df_cal_mode == CN.BRIR_DF_CAL_MODE_LIST[0]:
746+
brir_df_inv_fir = hf.build_min_phase_filter(smoothed_mag=brir_fft_avg_mag_inv, truncate_len=4096, n_fft=CN.N_FFT)
747+
elif brir_df_cal_mode == CN.BRIR_DF_CAL_MODE_LIST[1]:
748+
# 1. Define your impulse (e.g., 8192 samples long)
749+
n_fft_param = 8192
750+
impulse = np.zeros((1, 1, n_fft_param))
751+
impulse[0, 0, 0] = 1.0 # Set the first sample to 1.0
752+
# 2. Run your function with the override
753+
# This will return the EQ-IR as a (1, 1, n_fft) array
754+
eq_ir_dataset = hf.equalize_brirs_parametric(brir_dataset=impulse, diff_db_override=hf.mag2db(brir_fft_avg_mag_inv), override_n_fft=CN.N_FFT,
755+
num_filters=50,low_freq_cut = 12.0, high_freq_cut = 18000.0)
756+
# 3. Extract the 1D array for easy convolution later
757+
brir_df_inv_fir = eq_ir_dataset.flatten()
736758

737759
if report_progress > 0:
738760
progress = 80/100
@@ -751,7 +773,9 @@ def generate_integrated_brir(brir_name, spatial_res=1, report_progress=0, gui_l
751773
#larger reverb times will need additional samples
752774
#estimate output array length based on RT60
753775
#Below determines the most samples to keep based on estimated rt60
754-
if meas_rt60 <=400:
776+
if meas_rt60 <=0:
777+
out_samples_max = 512
778+
elif meas_rt60 <=400:
755779
out_samples_max = 33075
756780
elif meas_rt60 <=1250:
757781
out_samples_max = 64500
@@ -768,6 +792,8 @@ def generate_integrated_brir(brir_name, spatial_res=1, report_progress=0, gui_l
768792
crop_samples = hf.get_crop_index_relative(ref_array, tail_ignore=8000,head_ignore=100, threshold_db=reverb_tail_crop_db) #crop_samples = hf.get_crop_index(ref_array, tail_ignore=10000)
769793
if crop_samples < 2000 or crop_samples > out_samples_max:#ensure it stays within limits. Not suitable for short IRs (<50ms)
770794
crop_samples=out_samples_max
795+
if crop_samples > brir_max_length:#clamp to user specified max length
796+
crop_samples = brir_max_length
771797

772798
#merge filters into single EQ filter
773799
eq_filter = brir_df_inv_fir
@@ -1157,7 +1183,10 @@ def apply_peaking_filters(filter_seq, impulse, samp_freq):
11571183
{'fc': 10500, 'q': 5.0, 'gain_db': -3.0}],
11581184
'd': [{'fc': 3000, 'q': 2.0, 'gain_db': -6.0}, {'fc': 1500, 'q': 3.0, 'gain_db': 1.5}, {'fc': 5900, 'q': 3.0, 'gain_db': 3.5},
11591185
{'fc': 4500, 'q': 3.0, 'gain_db': 2.5}, {'fc': 9500, 'q': 7.0, 'gain_db': -4.0}, {'fc': 3600, 'q': 5.0, 'gain_db': -2.0},
1160-
{'fc': 10800, 'q': 4.0, 'gain_db': -2.0}, {'fc': 7700, 'q': 7.0, 'gain_db': 2.0}, {'fc': 6300, 'q': 7.0, 'gain_db': 1.0}]
1186+
{'fc': 10800, 'q': 4.0, 'gain_db': -2.0}, {'fc': 7700, 'q': 7.0, 'gain_db': 2.0}, {'fc': 6300, 'q': 7.0, 'gain_db': 1.0}],
1187+
'e': [{'fc': 1400, 'q': 2.5, 'gain_db': 1.0}, {'fc': 2100, 'q': 4.0, 'gain_db': -2.5}, {'fc': 2800, 'q': 2.5, 'gain_db': -3.0},
1188+
{'fc': 4500, 'q': 4.0, 'gain_db': -3.0}, {'fc': 5900, 'q': 2.0, 'gain_db': 1.0}, {'fc': 6600, 'q': 8.0, 'gain_db': -1.5},
1189+
{'fc': 7200, 'q': 4.0, 'gain_db': 4.0}, {'fc': 8200, 'q': 4.0, 'gain_db': 2.0}, {'fc': 10100, 'q': 9.0, 'gain_db': -7.0}, {'fc': 11000, 'q': 7.0, 'gain_db': -5.0}]
11611190
}
11621191

11631192
oe_hs_comp_mag = {}
@@ -1169,20 +1198,24 @@ def apply_peaking_filters(filter_seq, impulse, samp_freq):
11691198
hf.plot_data(np.abs(data_fft), f'oe_hs_comp_{key}_mag', normalise=1)
11701199

11711200
# Weighted average of HS comp a/b/c
1172-
oe_hs_comp_avg_db = np.sum([oe_hs_comp_mag[k]*w for k, w in zip(['a','b','c','d'], [0.25,0.15,0.15,0.45])], axis=0) * -1#0.4,0.3,0.3
1173-
oe_hs_new_avg_db = np.sum([oe_hs_comp_avg_db*0.6, hf.mag2db(over_ear_add_eq_mag)*0.4], axis=0)
1201+
oe_hs_comp_avg_db = np.sum([oe_hs_comp_mag[k]*w for k, w in zip(['a','b','c','d','e'], [0.17,0.17,0.17,0.29,0.20])], axis=0) * -1#0.4,0.3,0.3 - 0.25,0.15,0.15,0.45
1202+
oe_hs_new_avg_db = np.sum([oe_hs_comp_avg_db*0.70, hf.mag2db(over_ear_add_eq_mag)*0.30], axis=0)
11741203

11751204
# --- Final over-ear curves ---
11761205
over_ear_high_db = hf.mag2db(hp_est_avg_mag) + oe_hs_new_avg_db
11771206

11781207
if CN.PLOT_ENABLE:
1208+
oe_hs_comp_avg_mag = hf.db2mag(oe_hs_comp_avg_db)
11791209
oe_hs_new_avg_mag = hf.db2mag(oe_hs_new_avg_db)
11801210
oe_hs_new_avg_mag_inv = hf.db2mag(oe_hs_new_avg_db*-1)
11811211
over_ear_high_mag = hf.db2mag(over_ear_high_db)
11821212
in_ear_high_mag = hf.db2mag(in_ear_high_db)
11831213
in_ear_low_mag = hf.db2mag(in_ear_low_db)
1214+
11841215
hf.plot_data(hp_est_avg_mag, 'hp_est_avg_mag (Over ear HP Ear interactions, low strength)', normalise=1)
1185-
hf.plot_data(oe_hs_new_avg_mag, 'oe_hs_new_avg_mag (Over ear additional interactions)', normalise=1)
1216+
hf.plot_data(over_ear_add_eq_mag, 'over_ear_add_eq_mag (Over ear additional interactions v1)', normalise=1)
1217+
hf.plot_data(oe_hs_comp_avg_mag, 'oe_hs_comp_avg_mag (Over ear additional interactions v2)', normalise=1)
1218+
hf.plot_data(oe_hs_new_avg_mag, 'oe_hs_new_avg_mag (Over ear additional interactions v3 avg)', normalise=1)
11861219
hf.plot_data(oe_hs_new_avg_mag_inv, 'oe_hs_new_avg_mag_inv (Over ear additional interactions inverted)', normalise=1)
11871220
hf.plot_data(over_ear_high_mag, 'over_ear_high_mag (Over ear HP Ear interactions, high strength)', normalise=1)
11881221
hf.plot_data(in_ear_low_mag, 'in_ear_high_mag (In ear HP Ear interactions, low strength)', normalise=1)

0 commit comments

Comments
 (0)