API Reference

This page contains a listing of all the functions and classes in the library with their docstrings, neatly formatted and cross-referenced for your consumption.

Signals and Playback

class sound.signal.Signal[source]

The base class for all signal objects. Represents the abstract concept of a signal over time, sampled at the given sample rate.

Variables:
  • pure – A bool describing whether this signal is pure or not - a pure signal carries no internal state and any frame of it may be accessed in O(1) time.

  • duration – The length of this signal, in frames.

Several binary operators are overloaded so you may use them on Signal objects. A listing that ends with “Constants ok” means that you can use a contant integer or float where a signal is expected and it will be converted automatically to an infinitely long constant signal of that value.

  • +: You may add signals together to mix them together. Constants ok.

  • -: You may subtract signals and it’s like adding one to the inverse of the other. You may also negate a signal. Constants ok.

  • *: You may multiply two signals together to perform enveloping or amplitude modulation. Constants ok.

  • /: You may divide a signal by a number to reduce its amplitude by that factor.

  • >>: You may right-shift a signal by a number to delay it by that number of seconds.

  • <<: You may left-shift a signal by a number to move it back in time by that number of seconds.

  • &: You may and two signals together to concatenate them.

  • %: You may modulate a signal by a number to loop the first n seconds of it.

Additionally, you may use array slice notation to extract slices of sample data. The slice bounds are in seconds. Normal array indexing does not do anything.

play(length: float | None = None, progress=False)[source]

Play this signal. Block until playback is complete. If the given signal is infinitely long, default to three seconds of playback.

Parameters:
  • length – The length to play, in seconds. Optional.

  • progress – Whether to show a progress bar for rendering

async aplay(length: float | None = None)[source]

Play this signal. Block (but asyncio yield) until playback is complete. If the given signal is infinitely long, default to three seconds of playback.

Parameters:

length – The length to play, in seconds. Optional.

play_async()[source]

Play this signal asynchronously. Return the sounddevice stream object for this playback. The only way you should ever really have to interact with the return value of this function is to call .stop() on it.

Parameters:

thing – The signal to play

write(filename, length=None, progress=True)[source]

Write this signal to a .wav file.

Parameters:
  • filename – The filename to write to. Regardless of its extension, the output filetype will be uncompressed .wav

  • thing – The signal to write

render(length=None, progress=False, clip_warn=True)[source]

Render this signal into an numpy array of floats. Return the array.

Parameters:
  • length – The length to render, in seconds. Optional.

  • progress – Whether to show a progress bar for rendering

amplitude(frame: int) float[source]

The main interface for accessing sample data. This is the primary method that should be overridden by subclasses.

Parameters:

frame – The frame whose amplitude should be returned.

purify(preprocess=False) Signal[source]

Return a pure version of this signal. This is a no-op for pure signals, but for impure signals it installs a caching layer on top of the signal.

Parameters:

preprocess – Whether the cache should preload the sample data at initialize-time. Optional.

reverse() Signal[source]

Return a reversed version of this signal.

class sound.signal.LoopSignal(src, length)[source]

A signal that loops the first n seconds of its child

class sound.signal.DelaySignal(src, delay)[source]

A signal that delays its child by n seconds

delay is in samples

class sound.signal.SequenceSignal(*data)[source]

A sequence of signals starting at specific points in time. Ultimately used as an optimization for combinations of the >>, &, and + operators.

data is a sequence of tuples of (Signal, starttime) starttime is in samples

class sound.signal.InvertSignal(src)[source]

A signal that inverts its child

class sound.signal.ConstantSignal(amplitude)[source]

A signal that is a constant value

class sound.signal.MixSignal(*signals)[source]

A signal that mixes all its children together

class sound.signal.EnvelopeSignal(src, envelope)[source]

A signal that implements enveloping and amplitude modulation

class sound.signal.Purifier(src, length=None, preprocess=False)[source]

A signal that caches its child’s amplitude data

class sound.signal.SliceSignal(src, from_time, to_time, relative=False)[source]

A signal that extracts a slice of its child

class sound.signal.ReverseSignal(src)[source]

A signal that reverses its child

Basics - Samples and Envelopes

class sound.sample.RawData(data)[source]

A signal which is specified by an array of sample values.

static from_file(filename)[source]

Make a new RawData by loading from a .wav file.

static record(seconds)[source]

Make a new RawData by recording from the microphone.

class sound.tone.Sample(frequency)[source]

An infinitely long sound generated by a simple algorithm

class sound.tone.SineWave(frequency)[source]

A sample that outputs a sine wave at the given frequency

class sound.tone.SquareWave(frequency, split=0.5)[source]

A sample that outputs a square wave at the given frequency

Due to aliasing, you may want to use a series of sine wave harmonics if you want to obtain a more pleasant sound.

class sound.tone.SawtoothWave(frequency)[source]

A sample that outputs a sawtooth wave at the given frequency

Due to aliasing, you may want to use a series of sine wave harmonics if you want to obtain a more pleasant sound.

class sound.tone.TriangleWave(frequency)[source]

A sample that outputs a triangle wave at the given frequency

Due to aliasing, you may want to use a series of sine wave harmonics if you want to obtain a more pleasant sound.

class sound.tone.Noise[source]

A sample that outputs white noise, random data uniformly distributed over [0,1].

class sound.tone.BrownNoise(fac=0.5)[source]

A sample that outputs brown noise, the integration of white noise.

It is technically pure, but output may more closely resemble white noise if sample impurely.

class sound.tone.Digitar(frequency, buffersize=256, wavesrc=None)[source]

A sample that implements the Karplus-Strong plucked string synthesis algorithm. The basic idea is that an wavetable initially populated with random noise run though a low-pass filter cyclically, gradually removing inharmonic components and smoothing the waveform. The sound is tuned by keeping a separate “phase” counter which causes the output to cycle through the wavetable at a different speed than the filter, effectively adjusting the period of the signal. The decay rate is adjusted by changing the size of the wavetable - the smaller the wavetable, the faster the filter adjusts the signal and the faster that the sound decays. Keep in mind that if it decays very quickly, then the noise doesn’t have time to resolve into a tone, and the output will sound more drum-like.

Parameters:
  • frequency – The desired output frequency

  • buffersize – The size of the wavetable. Optional, defaults to a good plucked string sound.

  • wavesrc – A signal to sample to produce the initial wavetable. Optional, defaults to white noise.

sound.tone.harmonics(freq, ns=(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16), subsample=<class 'sound.tone.SineWave'>)[source]

Generate a number of harmonics of a given sample. The base tone is treated as the first harmonic.

Parameters:
  • freq – The base frequency to use

  • ns – A list of the harmonics to produce. Optional, defauts to the first 16 harmonics.

  • subsample – The class of the sample to use. Optional, defaults to a sine wave.

class sound.envelope.Envelope(duration)[source]

An envelope. This signal should not be a periodic waveform, but rather a broad shape.

You can use this base class to specify a square pulse for the given duration, in seconds.

apply_adsr(attack, decay, release, attack_level=1, sustain_level=0.5)[source]

Return the current envelope with an additional ADSR component. Parameters are the same as for the ADSR class initializer.

apply_decay(decay_param)[source]

Add an exponential decay to the current envelope.

Parameters:

decay_param – The speed of the decay, between 0 and 1. Lower values decay faster.

class sound.envelope.ADSR(attack, decay, sustain, release, attack_level: int | float = 1, sustain_level=0.5)[source]

An envelope with portions for Attack[1], Decay[2], Sustain[3], and Release[4]. You can also specify the attack level[5] and the sustain level[6]. Timing parameters are in seconds, level parameters are between 0 and 1.

   /\                    [5]
  /  \______________     [6]
 /                  \
/                    \
 [1] [2]   [3]     [4]
class sound.envelope.Decay(attack, sustain, release, decay_param=0.5, attack_level=1.0)[source]

An enevelope with an attack[1], an exponential decay[2], and a release[3]. You can specify the decay parameter[4] (between 0 and 1, smaller decays faster, and the height of the attack peak[5]. Times are given in seconds.

   /*.                    [5]
  /   *._
 /       **-..___       f = [4]^x
/                \
 [1]       [2]   [3]
class sound.envelope.Line(start, end, duration)[source]

A linear line running from start[1] to end[2] in a given time[3] in seconds.

*--__                   [1]
     *--__
          *--__
               *--__    [2]
       [3]
sound.envelope.envelope(sustain=None, attack=0.01, decay=None, release=None, attack_level: int | float = 1, sustain_level=0.7, decaying_sustain=True)[source]

A convenience method to produce an envelope for a musical instrument note. All parameters are optional and will pick sane defaults if not provided.

Parameters:
  • sustain – The length of the note (seconds)

  • atack – The length of the note’s attack (seconds)

  • decay

    if decaying_sustain:

    the exponential decay parameter.

    else:

    the length of the note’s decay (seconds)

  • attack_level – The intensity of the initial note attack

  • sustain_level – Only if not decaying_sustain, the intensity of the note’s sustained body

  • decaying_sustain – Whether the note’s sustaining period should involve exponential decay

Filters

class sound.filter.LowPassFilter(src, beta=0.5, pure=False, iir=True)[source]

Filter the argument signal, cutting out higher-frequency components.

The beta parameter controls the strength of the filter.

class sound.filter.BetterLowPassFilter(src, *params)[source]

This is a different implementation of the low pass filter. Pass it a signal to filter, and then a number of numerical parameters. Each frame of the output signal is the linear combination of the given parameters and the last n frames from the input signal. The last passes parameter corresponds with the most recent input frame.

class sound.filter.HighPassFilter(src, beta=0.5)[source]

Filter the input signal, cutting out low-frequency components.

The beta parameter controls the strength of the filter.

class sound.filter.FakeFMFilter(carrier_class, modulator, carrier_freq=440, mod_quantity=300)[source]

Don’t use this class please, I am so embarassed

class sound.filter.FMFilter(carrier, modulator, mod_quantity=300)[source]

Modulate the frequency of the carrier signal with the modulator signal. The strength of the modulator may be adjusted by the mod_quantity parameter.

sound.filter.ring_filter(data)[source]

Perform ring modulation on a given number of signals.

Parameters:

data – A list of signals to modulate together

sound.filter.bessel_wave(freq, alpha, beta)[source]

I literally don’t care if this isn’t technically a thing

Outputs an FM-synthesized sample with carrier frequency freq, modulator frequency freq * alpha, and modulator intensity beta

class sound.filter.PitchShift(src, shift)[source]

Perform a pitch shift on the source signal by the shift signal.

The value of the shift signal serves as a multiplier for the frequency of the source. Note that this works just by playing the source faster, so putting this on top of an enveloped sound is a bad idea, you need to put this under the envelope.

Instruments and Notes

class sound.instrument.Instrument(tempo=120, volume=1)[source]

A base class for instruments. An instrument is an object that can produce notes to a certain specification.

Parameters:

tempo – The tempo to produce notes at, in bpm. Optional, defaults to 120.

rest(beats=1)[source]

Return a rest for the given number of beats.

note(freq, beats=1, articulation=None)[source]

Return a note to the given specification.

Parameters:
  • freq – The frequency of the note to produce

  • beats – The number of beats to produce a note for, default 1

  • articulation – An optional number describing how legato or staccato notes should be produced, between 0 and 1. Larger values are more legato, smaller values are more staccato. Doesn’t work correctly for precussion or string instruments.

play(*args)[source]

Play a note to the given specification. Parameters are the same as those to note.

class sound.instrument.SineSustain(tempo=120, volume=1)[source]

A sustained sine tone.

Parameters:

tempo – The tempo to produce notes at, in bpm. Optional, defaults to 120.

class sound.instrument.SineHit(tempo=120, volume=1)[source]

A plucked sine tone. Sounds sort of xylophonish.

Parameters:

tempo – The tempo to produce notes at, in bpm. Optional, defaults to 120.

class sound.instrument.KickDrum(tempo=120, volume=1)[source]

A basic kick drum that’s just a low-frequency decaying sine wave. Frequency parameters are ignored.

Parameters:

tempo – The tempo to produce notes at, in bpm. Optional, defaults to 120.

class sound.instrument.Shaker(tempo=120, volume=1)[source]

A basic shaker precussion instrument that’s just decaying noise. Frequency parameters are ignored.

Parameters:

tempo – The tempo to produce notes at, in bpm. Optional, defaults to 120.

class sound.instrument.BassDrum(tempo=120, volume=1)[source]

A tuned bass drum, works by pitch-shifting a sine wave by a decaying value.

Parameters:

tempo – The tempo to produce notes at, in bpm. Optional, defaults to 120.

class sound.instrument.SquareViolin(tempo=120, volume=1)[source]

A violin made from a square wave.

Parameters:

tempo – The tempo to produce notes at, in bpm. Optional, defaults to 120.

class sound.instrument.HardDisk(tempo=120, volume=1)[source]

An instrument that sounds sort of like when people make music out of hard disks

Parameters:

tempo – The tempo to produce notes at, in bpm. Optional, defaults to 120.

class sound.instrument.ElectricHorn(tempo=120, volume=1)[source]

A horn-like sound made with FM synthesis

Parameters:

tempo – The tempo to produce notes at, in bpm. Optional, defaults to 120.

class sound.instrument.Bell(tempo=120, volume=1)[source]

A bell sound made from ring modulation. Doesn’t sound good at all frequencies.

Parameters:

tempo – The tempo to produce notes at, in bpm. Optional, defaults to 120.

class sound.instrument.Bell2(tempo=120, volume=1)[source]

Another bell, sounding more metallic, made from my horrible failed first attempt at FM synthesis. Doesn’t sound good at all frequencies.

Parameters:

tempo – The tempo to produce notes at, in bpm. Optional, defaults to 120.

class sound.instrument.ElectricBass(tempo=120, volume=1)[source]

An electric bass guitar, made with FM synthesis I think this one is my favorite.

Parameters:

tempo – The tempo to produce notes at, in bpm. Optional, defaults to 120.

class sound.instrument.Guitar(tempo=120, volume=1)[source]

A simple guitar made from Karplus-Strong plucked string synthesis

Parameters:

tempo – The tempo to produce notes at, in bpm. Optional, defaults to 120.

class sound.note.Note(src, value, beat)[source]

An abstraction over the signal base class to add timing information. The idea is that a note has a signal and then the value that that signal should be used as, in beats, in addition to the length of a beat.

All the binary operators on Sample objects now work with beats instead of seconds.

Parameters:
  • src – The signal to use as a source for the note

  • value – The value of the note in beats

  • beat – The length of a beat in samples

sound.notes.note(degree, octave=3, key='C', scale='major', accidental='')[source]

Return the frequency of the note with the given characteristics

Parameters:
  • degree – The scale degree of the note, zero-based

  • octave – The octave of the note

  • key – The key of the scale

  • scale – The name of the scale as a string. Options are “major”, “minor”, and “chromatic”.

  • accidental – The accidental for this note as a string. Options are “sharp”, “#”, or “s” for sharp, “flat”, “b”, or “f” for flat.

Note that accidentals do not respect the key - if you are in G major and you ask for the sixth degree (ti) sharpened, you will get back G, not F# like you would play if you were reading sheet music. Consequentially, there is no natural accidental.

sound.notes.notename(name)[source]

Translate the name of a note, like “A4”, into its frequency in hertz.

Utilities for Asynchronous Play

class sound.asyncplayer.AsyncPlayer[source]

An object useful for asynchronous play.

The idea is that you call .play_async() on it, then you can call .play() and .mute() on different sound objects to play or stop them in real time.

play(note)[source]
Parameters:

note – A Signal object to play, starting now.

mute(note)[source]
Parameters:

note – The sound object to mute. Works based on object identity.

queue(when, func, relative=True)[source]

Queue an event some number of frames in the future.

Parameters:
  • when – The number of frames in the future to perform the event

  • func – The thing to do in the future

  • relative – Optional. If set to false, when serves as an absolute timestamp since play started instead of a relative count.

If func is a callable object, it will be called. If func is a tuple, self.play() will be called with the tuple contents as args Other wise, self.play() will be called with func as an argument.

class sound.asyncplayer.KeyedAsyncPlayer[source]

An adaptation of AsyncPlayer to associate sounds with keys. This way, when you play another note under the same key, the first note that was played will be muted.

play(note, name=None)[source]
Parameters:
  • note – The sound to play

  • name – The key to play the sound under

mute(note)[source]
Parameters:

note – The key of the sound to mute

class sound.asyncplayer.InstrumentPlayer(instrument)[source]

An extension of KeyedAsyncPlayer where the keys are the frequencies of the notes being played, and .play() accepts arguments to an Instrument.note() call.

The idea is that this simulates an instrument where when you play two of the same note, the second note reuses the physical resource producing the sound for that note.

Parameters:

instrument – The instrument to play with

play(note, *args, **kwargs)[source]

All parameters are passed directly through to instrument.note()

class sound.asyncplayer.GuitarStrummer(sample)[source]

A guitar that you can strum in various chords!

strum_down(chord, delay=200)[source]

Strum the guitar in the given chord from top to bottom

Parameters:
  • chord – The chord to play, as a string. Look at the source for this class for a list of supported chords.

  • delay – The time inbetween chord plucks, in frames. Optional.

strum_up(chord, delay=200)[source]

Strum the guitar in the given chord from bottom to top

Parameters:
  • chord – The chord to play, as a string. Look at the source for this class for a list of supported chords.

  • delay – The time inbetween chord plucks, in frames. Optional.