music.localize2

music.localize2(sonic_vector=None, theta=-70, x=0.1, y=0.01, zeta=0.215, air_temp=20, method='ifft', sample_rate=44100)[source]

Make a mono sound stereo and localize it by experimental methods.

See below for implementation notes. These implementations are not standard and are only to illustrate the method of using ITD and IID that are frequency dependent.

Parameters:
sonic_vectorarray_like

A one-dimensional array with the PCM samples of the sound.

thetascalar or None

The azimuthal angle of the position in degrees, measured from straight ahead and positive to the left – not from the ear axis, as localize() and localize_linear() measure it. Only the side and how far round matter: the model has no distance, and cannot tell ahead from behind. If it is given, x and y are ignored. None places the source at x and y instead.

xscalar

The lateral component of the position in meters.

yscalar

The frontal component of the position in meters.

zetascalar

The distance between the ears in meters.

air_tempscalar

The temperature in Celsius used for calculating the speed of sound.

methodstr

Set to “ifft” for a working method that changes the fourier spectral coefficients. Set to “brute” for using an implementation that synthesizes each sinusoid in the fourier spectrum separately, from the bins holding all but the last 1% of the energy, counted from the lowest frequency up; it is slow, and its output is longer than the input by the largest interaural delay.

sample_rateinteger

The sample rate.

Returns:
sndarray

A (2, nsamples) shaped array with the PCM samples of the stereo sound.

Raises:
ValueError

If method is neither “ifft” nor “brute”. Those are the only two implemented, and a misspelling would otherwise fall through to whichever branch happened to be last.

See also

reverb

A reverberator.

localize

a more naive and fast implementation of localization by ITD and IID.

Notes

Works per frequency rather than on the sound as a whole: the delay between the ears is longer below 4 kHz than above it, and the shadow the head casts grows with frequency as 1 + (f/1000) ** .8 scaled by sin|theta|.

The article does not specify this model. It gives the geometric ITD and IID that localize() implements (its equations eq:dti and eq:dii), and then says in one sentence that low frequencies diffract and reach the far ear with a greater ITD; the crossover frequency, the two delay coefficients and the shadow exponent appear in none of its sources. This docstring used to say the calculations were “as described in [1]”, which they are not. What [1] does fix is the frequency a coefficient stands for, f_i = i * f_s / Lambda in eq:branco, and this routine had read it as twice that – see tests/test_article.py.

Treat the refinement as a rule of thumb that sounds better than the geometric model, not as a result the article supports. A full treatment needs an HRTF, which nothing here has.

See localize() for further notes.

Cite the following article whenever you use this function.

References

[1]

Fabbri, Renato, et al. “Musical elements in the discrete-time representation of sound.” arXiv preprint arXiv:abs/1412.6853 (2017)

Examples

>>> write_wav_stereo(localize2())
>>> # theta=None, or the default angle overrides every position
>>> write_wav_stereo(horizontal_stack(*[
...     localize2(note_with_vibrato(duration=1), theta=None, x=i, y=j)
...     for i, j in zip([.1, .7, np.pi - .1, np.pi - .7],
...                     [.1, .1, .1, .1])]))