Generating sounds

pyfxr has 3 sound generation algorithms, described below.

sfxr-style sounds

sfxr is a user interface for generating sounds with a wide array of parameters. pyfxr provides a full API to generate these sounds in Python programs.

class pyfxr.SFX(**kwargs)

Build a sound effect using a set of parameters.

The list of parameters is long and the sensible ranges for the parameters aren’t that clear. This class acts as a validator and builder for the parameters, making it simpler to experiment with sound effects.

You can also serialise this class in several ways:

  • The repr() is suitable for pasting into code.

  • You can serialise it as JSON using .as_dict().

  • You can pickle the class.

In any of these case the size is much smaller than the generated SoundBuffer.

SFX supports the buffer protocol much like SoundBuffer; accessing the object as a buffer generates and caches a sound.

base_freq: float

The initial frequency of the sound

freq_limit: float

The minimum frequency of the sound

freq_ramp: float

The rate of change of the frequency of the sound

freq_dramp: float

The acceleration of the change in frequency of the sound

duty: float

If using square wave, the duty cycle of the waveform

duty_ramp: float

The rate of change of the square wave duty cycle

vib_strength: float

Vibrato strength

vib_speed: float

Vibrato speed

vib_delay: float

Vibrato delay

env_attack: float

The duration of the attack phase of the ADSR envelope

env_sustain: float

The duration of the sustain phase of the ADSR envelope

env_decay: float

The duration of the decay phase of the ADSR envelope

env_punch: float

Causes the volume to decrease during the sustain phase of the envelope

lpf_resonance: float

Low-pass filter resonance

lpf_freq: float

Low-pass filter cutoff frequency

lpf_ramp: float

Low-pass filter cutoff ramp

hpf_freq: float

High-pass filter frequency

hpf_ramp: float

High-pass filter ramp

pha_offset: float

Phaser offset

pha_ramp: float

Phaser ramp

repeat_speed: float

Repeat speed

arp_speed: float

Arpeggio speed

arp_mod: float

Arpeggio mod

property wave_type

Get the wave type.

as_dict()dict

Get the parameters as a dict.

The dict is suitable for serialising as JSON; to reconstruct the object, pass the parameters as kwargs to the constructor, eg.

>>> s = SFX(...)
>>> params = s.as_dict()
>>> s2 = SFX(**params)
build()_pyfxr.SoundBuffer

Get the generated sound (memoised).

envelope(attack: float = 0.0, sustain: float = 0.3, decay: float = 0.4, punch: float = 0.0)

Set the ADSR envelope for this sound effect.

The wave_type of an SFX must be one of these values:

class pyfxr.WaveType(value)

The wave types available for the SFX builder.

Pure tones with tone() use arbitrary wavetables rather than this enumeration.

SQUARE = 0

A square-wave waveform

SAW = 1

A saw-wave waveform

SINE = 2

A sine wave

NOISE = 3

Random noise

You can also randomly generate those parameters:

pyfxr.pickup()pyfxr.SFX

Generate a random bell sound, like picking up a coin.

pyfxr.laser()pyfxr.SFX

Generate a random laser sound.

pyfxr.explosion()pyfxr.SFX

Generate a random explosion sound.

pyfxr.powerup()pyfxr.SFX

Generate a random chime, like receiving a power-up.

pyfxr.hurt()pyfxr.SFX

Generate a random impact sound, like a character being hurt.

pyfxr.jump()pyfxr.SFX

Generate a random jump sound.

pyfxr.select()pyfxr.SFX

Generate a random ‘blip’ noise, like selecting an option in a menu.

Wavetable sounds

pyfxr can also generate pure tones using a wavetable. A wavetable gives the shape of a waveform, such as these:

(Source code, png, hires.png, pdf)

_images/generating-1.png

Wavetables can have any shape. To construct a Wavetable with a custom shape, pass an iterable to the constructor. This should return 1024 float values in [-1, 1].

from math import pi, sin
from pyfxr import Wavetable

def gen():
    for i in range(1024):
        t = pi / 512 * i
        yield 0.75 * sin(t) + 0.25 * sin(3 * t + 0.5)

wt = Wavetable(gen())

Or perhaps more simply, use Wavetable.from_function():

Wavetable.from_function(
    lambda t: 0.75 * sin(t) + 0.25 * sin(3 * t + 0.5)
)

(Source code, png, hires.png, pdf)

_images/generating-2.png
class pyfxr.Wavetable(gen)
static from_function(f)

Generate a wavetable by calling a function f.

f should take a single float argument between 0 and tau (pi * 2) and return values in [-1, 1].

static saw()

Construct a saw waveform.

static sine()

Construct a sine waveform.

static square(float duty_cycle=0.5)

Generate a square-wave waveform.

duty_cycle is the fraction of the period during which the waveform is greater than zero.

static triangle()

Construct a triangle waveform.

pyfxr.tone(pitch: Union[float, str] = 440.0, attack: float = 0.1, decay: float = 0.1, sustain: float = 0.75, release: float = 0.25, wavetable: _pyfxr.Wavetable = <_pyfxr.Wavetable object>)_pyfxr.SoundBuffer

Generate a tone using a wavetable.

The tone will be modulated by an ADSR envelope (attack-decay-sustain-release) which gives the tone a more natural feel, and avoids clicks when played. The total length of the tone is the sum of these durations.

Parameters
  • wavetable – The wavetable to use (default is a sine wave).

  • pitch – The pitch of the tone to generate, either float Hz or a note name/number like Bb4 for B-flat in the 4th octave.

  • attack – Attack time in seconds

  • decay – Decay time in seconds

  • sustain – Sustain time in seconds

  • release – Release time in seconds

ADSR Envelopes

Tones are bounded by a 4-phase “ADSR Envelope”. The phases are:

  • Attack - initial increase in volume

  • Decay - volume decreases to the sustain level

  • Sustain - the volume stays constant while the note is held

  • Release - the volume fades to zero

(Source code, png, hires.png, pdf)

_images/generating-3.png

The default ADSR envelope has this shape. Note that durations for any of the ADSR phases can be set to zero to omit that phase. It is recommended to skip only decay and sustain phases, as attack and release phases help to avoid clicks when the sound plays.

This is applied to a waveform by multiplication:

(Source code, png, hires.png, pdf)

_images/generating-4.png

Pluck sounds

pyfxr can also generate pluck sounds, like a guitar or harp.

pyfxr.pluck()

pluck(float duration, float pitch, float release=0.1) Generate a pluck sound using the Karplus-Strong algorithm.