music.reverb

music.reverb(duration=1.9, first_phase_duration=0.15, decay=-50, noise_type='brown', sonic_vector=0, sample_rate=None, seed=None)[source]

Apply an artificial reverberation or return the impulse response.

Parameters:
durationscalar

The total duration of the reverberation in seconds.

first_phase_durationscalar

The duration of the first phase of the reverberation in seconds.

decayscalar

The total decay of the last incidence in decibels.

noise_typestr or scalar

The colour of the noise the second period is made of, passed to noise() as its noise_type.

sonic_vectorarray_like

An optional one dimensional array for the reverberation to be applied.

sample_ratescalar or None

The sampling frequency. None, the default, is the rate music.get_sample_rate() returns.

seedinteger or None

A seed for the incidences and the noise, as noise() takes one: the same seed draws the same room again, and leaves NumPy’s global random state alone. None, the default, draws from that state, as this always did.

Returns:
resultnumpy.ndarray

An array with the impulse response of the reverberation. If sonic_vector is specified, the reverberation applied to sonic_vector.

Raises:
ValueError

If first_phase_duration is negative or longer than duration, sample_rate is not positive, or duration is shorter than one sample: the response begins with the direct sound, so it has at least that.

If sonic_vector is not one-dimensional: numpy said “object too deep for desired array”. Reverberate each channel, or mix them down first.

If seed is not a whole number in [0, 2**64).

Parameters:
  • duration (float)

  • first_phase_duration (float)

  • decay (float)

  • noise_type (str | float)

  • sonic_vector (ArrayLike)

  • sample_rate (int | None)

  • seed (int | None)

Return type:

NDArray[float64]

Notes

The impulse response has the article’s two periods [1]. Over the first, of \(\Lambda_1\) samples, the sound comes back at sample \(i\) with the probability \(p_i = (i / \Lambda_1)^2\) (eq:p1rev); over the rest of the \(\Lambda_R\), it comes back as noise_type noise \(r^b_i\) (eq:p2rev). Both decay by decay decibels, \(V_{dB}\), across the whole response:

\[\begin{split}r_i = 10^{\frac{V_{dB}}{20} \frac{i}{\Lambda_R - 1}} \times \begin{cases} 1 \text{ with probability } p_i, \text{ else } 0, & i < \Lambda_1, \\ r^b_i, & \Lambda_1 \le i < \Lambda_R, \end{cases}\end{split}\]

with \(r_0 = 1\), the direct sound (eq:rev). Given a sonic_vector, it returns the sound convolved with \(r\), which is longer than the sound by \(\Lambda_R - 1\) samples. Unlike the article’s, the reflections are not filtered by the surfaces they meet, so every frequency decays alike. For a stereo room, reverberate each channel with a different seed.

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

>>> impulse = reverb(duration=1.9, first_phase_duration=0.15, decay=-50)
>>> round(float(impulse[0]), 3)     # the direct sound
1.0
>>> wet = reverb(sonic_vector=note(440, 1), duration=0.5)
>>> len(wet) > 44100                # longer than the note by its tail
True