music.pan_transitions

music.pan_transitions(p=((1, 1), (1, 0), (0, 1), (1, 1)), d=(2, 2, 2), method='lin', sample_rate=None, sonic_vector=None)[source]

Applies pan transitions to a sonic vector.

Parameters:
plist of tuples, optional

List of pan positions, where each tuple represents the amplitude envelope of each channel, by default [(1,1),(1,0),(0,1),(1,1)]

dlist, optional

The duration of each transition in seconds, by default [2,2,2]. Durations past the last transition are not read.

methodstr or list, optional

How each transition moves: ‘lin’, ‘circ’ or ‘exp’, described below. One name is the law of every transition, and a list holds one for each, by default ‘lin’. Names past the last transition are not read.

sample_rateint or None, optional

Sample rate of the audio. None, the default, is the rate music.get_sample_rate() returns.

sonic_vectorndarray, optional

A mono or stereo sound to pan. Without one, the two envelopes themselves are returned.

Returns:
ndarray

The (2, n) panning envelopes, or sonic_vector scaled by them: as long as the sound, holding the last position past the end of the transitions.

Raises:
ValueError

If there are fewer durations or methods than transitions, or a method is not one of the three. A short list used to reach an IndexError from inside the routine.

If a transition by ‘circ’ or ‘exp’ starts or ends at a negative amplitude: they are laws of a channel’s power and loudness, which have no sign.

Notes

Each pan transition i takes the amplitude of channel c from p[i][c] toward p[i+1][c], which the next transition starts at, by the law method[i]. Over progress x from 0 toward 1, from amplitude a to b:

'lin', linear in amplitude:
    a*(1 - x) + b*x
'circ', linear in power along a quarter circle:
    sqrt((a*cos(pi*x/2))**2 + (b*sin(pi*x/2))**2)
'exp', linear in decibels:
    a*(b/a)**x

‘exp’ to or from silence, where decibels run out, is fade()’s exponential fade: 80 dB of it, then a linear one percent to silence. Across (1, 0) to (0, 1), ‘lin’ keeps the sum of the channels’ amplitudes and lets their power dip 3 dB halfway; ‘circ’ keeps their power, since cos(x)**2 + sin(x)**2 = 1; ‘exp’ changes each channel’s loudness at a steady rate and keeps neither. Until 2.0.0 method was not read, and every transition was ‘lin’.

For now, each channel’s signal are kept from mixing. One immediate possibility is to maintain the expected tessitura of the sample amplitudes. Say p = [.5,1,0,.5] ~ [(1,1),(1,0),(0,1),(1,1)]. Then pi,pj = .5,1 might be performed as:

s1 = s1*.5 -> 0
s2 = s1*.5 -> (s1+s2)*.5

Or through sinusoids and exponentials

Make fast and slow fades and parameter transitions using weber-fechner and steven’s laws. E.g.:

pitch_trans = [pitch0*X**(i/Y) for i in range(12)]
pitch_trans = [pitch0 + X*i**Y for i in range(12)]

Examples

>>> p = [(0, 1), (1, 0), (0, 1), (1, 1)]
>>> d = [2, 2, 2]
>>> method = ['lin', 'circ', 'exp']
>>> sonic_vector = np.random.rand(2, 44100 * 6)  # Random stereo signal
>>> result = pan_transitions(p, d, method, sonic_vector=sonic_vector)