08-handling-channels.py - Managing object’s internal audio streams.

Because audio objects expand their number of streams according to lists given to their arguments and the fact that an audio object is considered as a list, if a multi-streams object is given as an argument to another audio object, the later will also be expanded in order to process all given streams. This is really powerful to create polyphonic processes without copying long chunks of code but it can be very CPU expensive.

In this example, we create a square from a sum of sine waves. After that, a chorus is applied to the resulting waveform. If we don’t mix down the square wave, we got tens of Chorus objects in the processing chain (one per sine). This can easily overrun the CPU. The exact same result can be obtained with only one Chorus applied to the sum of the sine waves. The mix(voices) method of the PyoObject helps the handling of channels in order to save CPU cycles. Here, we down mix all streams to only two streams (to maintain the stereo) before processing the Chorus arguments.

from pyo import *

s = Server().boot()

# Sets fundamental frequency and highest harmonic.
freq = 100
high = 20

# Generates lists for frequencies and amplitudes
harms = [freq * i for i in range(1, high) if i % 2 == 1]
amps = [0.33 / i for i in range(1, high) if i % 2 == 1]

# Creates a square wave by additive synthesis.
a = Sine(freq=harms, mul=amps)
print("Number of Sine streams: %d" % len(a))

# Mix down the number of streams of "a" before computing the Chorus.
b = Chorus(a.mix(2), feedback=0.5).out()
print("Number of Chorus streams: %d" % len(b))

s.gui(locals())