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=None)[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()andlocalize_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.
- method
str 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_rate
integerorNone The sample rate. None, the default, is the rate
music.get_sample_rate()returns.
- Returns:
- s
ndarray A (2, nsamples) shaped array with the PCM samples of the stereo sound.
- s
- Raises:
ValueErrorIf
methodis neither “ifft” nor “brute”. Those are the only two implemented, and a misspelling would otherwise fall through to whichever branch happened to be last.If sonic_vector is not one-dimensional. A stereo sound came back as four channels of nothing in particular, with no error at all; the routine places one source, so mix the channels down first.
If zeta is negative: it is the distance between the ears, and below zero the interaural delay reached numpy as an array of negative length.
See also
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) ** .8scaled bysin|theta|.The article does not specify this model. It gives the geometric ITD and IID that
localize()implements (its equationseq:dtiandeq: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 / Lambdaineq:branco, and this routine had read it as twice that – seetests/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:
localize_hrtf()applies a measured one, whichhrir()reads.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])]))