music.Bonds

class music.Bonds(**relations)[source]

Bases: object

A set of relations tying a note’s characteristics to its frequency.

Each keyword is one of BINDABLE, and its value is either a callable of the frequency – the func_a, func_b and func_c of eq:vinculos – or a constant, for a characteristic that does not vary. Anything left unbound keeps the synthesis routine’s own default.

Parameters:
**relations

The bonds, by the name of what they set.

Raises:
ValueError

If a keyword is not one of BINDABLE.

See also

proportional

a bond rising with the frequency.

inversely_proportional

a bond falling with it.

stepped

a bond that changes by register.

note_with_vibrato

what a bound vibrato is applied through.

tremolo

what a bound tremolo is applied through.

Notes

The article gives no functions, and neither does this: what makes a set of bonds musical is a decision about a piece, not a fact about synthesis. What it fixes is that the decision is made once and applies to every note, which is the difference between a bond and a parameter.

Examples

>>> language = Bonds(vibrato_freq=proportional(1 / 50),
...                  max_pitch_dev=2.0)
>>> language.characteristics(440)['vibrato_freq']
8.8
>>> language.characteristics(440)['max_pitch_dev']
2.0
>>> sound = language.render([220, 440], duration=0.2)
>>> len(sound)
17640
__init__(**relations)[source]
Return type:

None

Methods

__init__(**relations)

characteristics(freq)

What every bond says about a note at freq.

note([freq, duration, sample_rate])

One note, with every bond applied to it.

render(freqs[, duration, sample_rate])

A sequence of notes, each bound to its own frequency.

characteristics(freq)[source]

What every bond says about a note at freq.

Parameters:
freqscalar

The note’s frequency in Hertz.

Returns:
dict

One entry per bond, with the value it gives at that frequency. A callable bond is called; a constant is returned as it is.

Parameters:

freq (float)

Return type:

dict[str, float]

Examples

>>> Bonds(max_db_dev=proportional(1 / 20)).characteristics(200)
{'max_db_dev': 10.0}
note(freq=220.0, duration=2.0, sample_rate=44100)[source]

One note, with every bond applied to it.

A bound vibrato is rendered through note_with_vibrato(), and a bound tremolo is a tremolo() envelope over it. With neither bound this is note().

Parameters:
freqscalar

The note’s frequency in Hertz, which every bond is a function of.

durationscalar

Its duration in seconds.

sample_rateinteger

The sample rate.

Returns:
ndarray

The note.

Parameters:
Return type:

NDArray[float64]

Examples

>>> plain = Bonds().note(freq=440, duration=0.1)
>>> np.array_equal(plain, note(freq=440, duration=0.1))
True
render(freqs, duration=2.0, sample_rate=44100)[source]

A sequence of notes, each bound to its own frequency.

Parameters:
freqssequence of scalars

The frequencies, in order.

durationscalar or sequence of scalars

One duration for every note, or one per note.

sample_rateinteger

The sample rate.

Returns:
ndarray

The notes, end to end.

Raises:
ValueError

If freqs is empty, or if a sequence of durations is not as long as it.

Parameters:
Return type:

NDArray[float64]

Examples

>>> language = Bonds(vibrato_freq=proportional(1 / 40))
>>> len(language.render([220, 440, 330], duration=0.1))
13230
>>> len(language.render([220, 440], duration=[0.1, 0.3]))
17640