2. How to create a basic kick drum with pitch and gain envelopes

First, we need to import some oscillators and the GlobalTransport, like in the previous tutorial. We will also need some effects processors to control gain and signal linearity.

from py_modular.sound.oscillators import Sine, Saw
from py_modular.effects.mixer import Atten, LinToExp
from py_modular.time.transport import GlobalTransport

We will start by writing a quick wrapper to easily create envelopes. For the purpose of this tutorial, we will be shaping a saw wave and using it as an envelope, but there are many other ways it could be done. Since we want our envelopes to go from high to low, we will apply a gain of -1.0 to the saw signal to invert it. After creating a saw wave, we can use the LinToExp effect node to shape the wave. Adding a curve parameter to the processor will allow us to turn a linear signal into an exponential or logarithmic-type signal. Lastly, we will put the signal through an attenuator.

def create_envelope(freq, curve, gain, offset):
    envelope_base = Saw(freq=freq, gain=-1.0)
    curved_envelope = LinToExp(envelope_base, curve)
    offset_envelope = Atten(curved_envelope, gain=gain, offset=offset)
    return offset_envelope

For the gain envelope, we want the gain to be above 0, since a negative gain will only invert the wave. Since the saw wave we are basing these envelopes on oscillate between -1.0 and 1.0, we need a gain and offset of 0.5 to transform the signal into the 0.0 to 1.0 range.

gain_envelope = create_envelope(1, 0.8, 0.5, 0.5)

For the pitch envelope, since we are working in Hz, we will increase the gain and offset substantially, so we can be sure it will be in our auditory range.

pitch_envelope = create_envelope(1, 0.9, 10, 10)

To complete the kick, we will use another sine wave as a base and apply the gain and pitch envelopes correspondingly.

kick = Sine(freq=60, gainct=gain_envelope, fmct=[pitch_envelope])

To complete it, we can follow the same steps as the last tutorial to play our audio. Put everything in the global transport, then run python simple_kick_drum.py and you should hear a kick sound.

global_transport = GlobalTransport([], input_device=15, output_device=15)
global_transport.chs[0].add_node(kick)
global_transport.chs[1].add_node(kick)

global_transport.start()

You should have something that sounds like this