music.spatial_motion

music.spatial_motion(carrier_freq=200.0, motion_rate=0.2, duration=2.0, theta1=180.0, theta2=0.0, dist=0.1, sonic_vector=None, waveform_table=array([0., 0.0003835, 0.00076699, ..., -0.00115049, -0.00076699, -0.0003835], shape=(16384,)), zeta=0.215, air_temp=20.0, number_of_samples=0, sample_rate=44100)[source]

Orbit a source around the listener: sstim-v:techSpatialAuditory.

A sound whose apparent position sweeps back and forth between two azimuths at a chosen rate. SSTIM catalogues structured spatial trajectories – orbiting sources, lateral sweeps, spatial alternation – as techSpatialAuditory, and distinguishes them from simple left/right crossfades [2]. This is on the right side of that line: the two ears receive the interaural time and intensity differences the geometry implies, computed per sample, not a pan between two gains.

Parameters:
carrier_freqscalar

The frequency of the orbiting tone, in Hertz. Ignored when sonic_vector is given.

motion_ratescalar

How many round trips the source makes per second, in Hertz. One cycle is a full there-and-back, so the source passes each endpoint once per cycle.

durationscalar

The duration in seconds.

theta1scalar

The azimuth the motion starts from, in degrees, measured from the ear axis as in music.localize_linear(): 0 is the right ear’s side, 180 the left. The default is a full crossing of the head.

theta2scalar

The azimuth it travels to before returning, in degrees.

distscalar

The radius of the orbit, in meters.

sonic_vectorarray_like or None

A mono sound to move instead of a synthesized tone, so a noise bed or a rendered stimulus can be given a trajectory. When it is given it sets the length, and duration, number_of_samples, carrier_freq and waveform_table are not used.

waveform_tablearray_like

The table the tone is looked up in.

zetascalar

The distance between the ears in meters.

air_tempscalar

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

number_of_samplesinteger

The number of samples of the sound, taken instead of duration when it is given.

sample_rateinteger

The sampling frequency in Hertz.

Returns:
ndarray

A (2, nsamples) array of stereo PCM samples.

Raises:
ValueError

If motion_rate is negative, which would reverse the trajectory rather than slow it.

ValueError

If sonic_vector is not one-dimensional. A stereo sound has its position already, and moving one failed inside the localization with a message about broadcasting.

Parameters:
  • carrier_freq (float)

  • motion_rate (float)

  • duration (float)

  • theta1 (float)

  • theta2 (float)

  • dist (float)

  • sonic_vector (ArrayLike | None)

  • waveform_table (ArrayLike)

  • zeta (float)

  • air_temp (float)

  • number_of_samples (int)

  • sample_rate (int)

Return type:

NDArray[float64]

See also

music.localize_linear

one straight pass, the primitive underneath.

music.note_with_doppler

a moving source synthesized rather than filtered, so it also shifts pitch.

Notes

The motion is physically present: the cues are in the signal, and a recording of the output carries them.

The source travels along the arc at constant radius – an orbit – where music.localize_linear() travels the straight line between its two endpoints, which is what makes that one linear. The azimuth moves at a constant rate, so the trajectory is triangular in angle and the source neither pauses nor lurches at the turns.

There is no head-related transfer function here, as there is none anywhere in this package. Interaural time and intensity differences place a source on the left-right axis and nothing else: elevation, and whether the source is in front of or behind the listener, are cues an HRTF carries and this does not. An orbit rendered here is heard as a lateral sweep rather than as a circle around the head, and an orbit between 90 and -90 degrees – ahead and behind – renders no movement whatsoever, because those two positions differ only in the cue that is missing.

References

[1]

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

[2]

SSTIM, techSpatialAuditory. https://w3id.org/sstim/vocab#techSpatialAuditory

Examples

>>> stimulus = spatial_motion(carrier_freq=200, motion_rate=0.5)
>>> stimulus.shape[0]
2