def interaural_level_spectrum(self, azimuth, level_spectrum_filter=None): ''' Apply a frequency-dependend interaural level difference corresponding to a given azimuth to a binaural sound. The level difference cues are taken from a filter generated with the _make_level_spectrum_filter function from an hrtf recording. The default will generate the filter from the MIT KEMAR recordings. The left and right channel of the sound should have the same level. Example: >>> noise = Binaural.pinknoise(kind='diotic') >>> noise.interaural_level_spectrum(azimuth=-45).play() ''' if not level_spectrum_filter: ils = Binaural._make_level_spectrum_filter( ) # TODO: should cache this as a file in /data or global ils = ils[:, 1:] # remove the frequency values (not necessary here) azis = ils[0, :] # get vector of azimuths in ils filter bank ils = ils[1:, :] # the rest is the filter # interpolate levels at azimuth levels = [ numpy.interp(azimuth, azis, ils[:, i]) for i in range(ils.shape[1]) ] fbank = Filter.cos_filterbank(length=self.nsamples, samplerate=self.samplerate) subbands_left = fbank.apply(self.left) subbands_right = fbank.apply(self.right) # change subband levels: subbands_left.level = subbands_left.level + levels / 2 subbands_right.level = subbands_right.level - levels / 2 out_left = Filter.collapse_subbands(subbands_left, filter_bank=fbank) out_right = Filter.collapse_subbands(subbands_right, filter_bank=fbank) return Binaural([out_left, out_right])
def interaural_level_spectrum(self, azimuth, ils=None): """ Apply an interaural level spectrum, corresponding to a sound sources azimuth, to a binaural sound. The interaural level spectrum consists of frequency specific interaural level differences which are computed from a head related transfer function (see the `make_interaural_level_spectrum()` method). The binaural sound is divided into frequency sub-bands and the levels of each sub-band are set according to the respective level in the interaural level spectrum. Then, the sub-bands are summed up again into one binaural sound. Arguments: azimuth (int | float): azimuth for which the interaural level spectrum is calculated. ils (dict): interaural level spectrum to apply. If None, `make_interaural_level_spectrum()` is called. For repeated use, it is better to generate and keep the ils in a variable to avoid re-computing it. Returns: (slab.Binaural): A binaural sound with the interaural level spectrum corresponding to the given azimuth. Examples:: noise = slab.Binaural.pinknoise(kind='diotic') ils = slab.Binaural.make_interaural_level_spectrum() # using default KEMAR HRTF noise.interaural_level_spectrum(azimuth=-45, ils=ils).play() """ if ils is None: ils = Binaural.make_interaural_level_spectrum() ils_samplerate = ils['samplerate'] original_samplerate = self.samplerate azis = ils['azimuths'] level_diffs = ils['level_diffs'] levels = numpy.array([numpy.interp(azimuth, azis, level_diffs[i, :]) for i in range(level_diffs.shape[0])]) # resample the signal to the rate of the HRTF from which the filter was computed: resampled = self.resample(samplerate=ils_samplerate) fbank = Filter.cos_filterbank(length=resampled.n_samples, samplerate=ils_samplerate, pass_bands=True) subbands_left = fbank.apply(resampled.left) subbands_right = fbank.apply(resampled.right) # change subband levels: subbands_left.level = subbands_left.level + levels / 2 subbands_right.level = subbands_right.level - levels / 2 out_left = Filter.collapse_subbands(subbands_left, filter_bank=fbank) out_right = Filter.collapse_subbands(subbands_right, filter_bank=fbank) out = Binaural([out_left, out_right]) return out.resample(samplerate=original_samplerate)