music.isochronic_tones

music.isochronic_tones(carrier_freq=200.0, pulse_rate=10.0, duty_cycle=0.5, duration=2.0, ramp_duration=0.0, waveform_table=array([0., 0.0003835, 0.00076699, ..., -0.00115049, -0.00076699, -0.0003835], shape=(16384,)), number_of_samples=0, sample_rate=44100)[source]

Synthesize an isochronic tone train: sstim-v:techIsochronicTones.

A single tone switched on and off at evenly spaced intervals – a gated pulse train – at a target rate; a monaural, single-channel entrainment stimulus [2].

Parameters:
carrier_freqscalar

The frequency of the gated tone, in Hertz.

pulse_ratescalar

How many times per second the tone is switched on, in Hertz.

duty_cyclescalar

The fraction of each pulse period the tone is on, in (0, 1].

durationscalar

The duration in seconds.

ramp_durationscalar

A linear fade in and out applied at each pulse edge, in seconds. Zero, the default, gates abruptly, which is the literal technique; see the note below on what that costs. A ramp longer than half the sounding part of a pulse leaves the two ramps overlapping, and the pulse becomes a triangle that never reaches full amplitude rather than an error.

waveform_tablearray_like

The table the tone is looked up in.

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 mono sequence of PCM samples.

Raises:
ValueError

If duty_cycle is outside (0, 1]. A duty cycle of zero is silence and one above one is not a gate, and both are more likely to be a mistake than an intention.

ValueError

If ramp_duration is negative, which would otherwise scale every pulse by a clipped negative and return silence.

Parameters:
  • carrier_freq (float)

  • pulse_rate (float)

  • duty_cycle (float)

  • duration (float)

  • ramp_duration (float)

  • waveform_table (ArrayLike)

  • number_of_samples (int)

  • sample_rate (int)

Return type:

NDArray[float64]

Notes

The modulation is physically present, and at pulse_rate rather than at carrier_freq.

An abrupt gate is what the technique names, but it is also a step discontinuity twice per pulse, and each step spreads energy across the spectrum – audible as a click, and visible in a recording as broadband splatter that is not part of the intended stimulus. Set ramp_duration to a few milliseconds to taper the edges when the stimulus is going to be measured or listened to for any length of time.

References

[1]

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

[2]

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

Examples

>>> stimulus = isochronic_tones(pulse_rate=10, duty_cycle=0.5)
>>> stimulus.ndim
1