The audiomath package

Summary

audiomath is a package for reading, manipulating, and writing sound waveforms. It also lets you record and play sounds, with a high degree of real-time control over playback.

To manipulate sound waveforms, plot them, and write them to disk, use the Sound class. Usually you would initialize a Sound instance from a filename, or from a numpy array—in the latter case your array would contain floating-point values in the range [-1, +1], arranged samples-by-channels.

To play sounds, use the Player class. You can initialize a Player instance from a Sound instance, or from anything that can be used to create one (e.g. a filename). You can also supply a sequence of Sound instances, or a sequence of filenames or a glob pattern that matches multiple files: then you can have the Player instance manage multiple “tracks”. Each Player will only play one sound at a time: to overlap sounds, create multiple Player instances.

To record a sound, use the Record function, or the Recorder class if you want to do it asynchronously.

Classes

Global functions and constants

audiomath.Concatenate(*args)

Concatenate sounds in time, to make a new Sound instance containing a new array.

You can also concatenate Sound instances using the % operator, and can modifying an existing Sound instance s (replacing its array s.y) using %=:

s = s1 % s2
s %= s1

Note that, in the above examples, either s1 or s2 may also be a numeric scalar: s %= 0.5 appends half a second of silence to s.

audiomath.MakeFall(duration, fs=1000, hann=False)

Return a single-channel Sound object of the specified duration in seconds at the specified sampling frequency fs in Hz, containing a “fade-out” envelope (i.e. a ramp from 1 to 0). If hann is True, use a raised-cosine profile instead of a linear ramp.

See also: MakeRise(), MakePlateau(), MakeHannWindow()

audiomath.MakeHannWindow(duration, fs=1000, plateau_duration=0)

Return a single-channel Sound object of the specified duration in seconds at the specified sampling frequency fs in Hz, containing a Hann or Tukey window—i.e. a raised-cosine “fade-in”, followed by an optional plateau, followed by a raised-cosine “fade-out”.

See also: MakeRise(), MakePlateau(), MakeFall()

audiomath.MakePlateau(duration, fs=1000, dc=1.0)

Return a single-channel Sound object of the specified duration in seconds at the specified sampling frequency fs in Hz, containing a constant dc value.

See also: MakeRise(), MakeFall(), MakeHannWindow()

audiomath.MakeRise(duration, fs=1000, hann=False)

Return a single-channel Sound object of the specified duration in seconds at the specified sampling frequency fs in Hz, containing a “fade-in” envelope (i.e. a ramp from 0 to 1). If hann is True, use a raised-cosine profile instead of a linear ramp.

See also: MakePlateau(), MakeFall(), MakeHannWindow()

audiomath.QueueTest()

Construct and return an example Queue containing example Sound instances. Initialize a Player with this to test management of multiple tracks by the Player class.

audiomath.Record(space=60, prompt=None, verbose=None, cut=True, nChannels=None, filename=None, **kwargs)

Record and return a Sound synchronously. Slightly easier than creating your own Recorder instance and working with that (which is what you would have to do if you want to record asynchronously).

Parameters:
  • space (Sound, float) – specifies either a pre-existing Sound instance into which to record, or a number of seconds. In the latter case a Sound instance is created, pre- allocated with the specified amount of space in seconds.

  • prompt (None, bool, str, function) – if this is left as None, a default string is composed. If prompt is a string, it is printed to the console and the Recorder waits until it has finished (or until ctrl-C is pressed). Alternatively, supply a callable whose non-None return value signals that the recording should end.

  • verbose (bool) – Passed through to the constructor of the Recorder object that is being used.

  • cut (bool) – If true, return a Cut() version of the Sound when recording stops—i.e. ensure that the duration of the Sound does not exceed the duration of the recording. If false, the entire pre-allocated space is returned, with the recording at the beginning.

  • nChannels (int) – Optionally specify the number of channels to record (some APIs have crazy defaults, like ALSA’s 32 channels - if you’re not using one of those APIs, you probably don’t need this).

  • filename (str) – Optionally, use the ffmpeg class to stream the recorded content to the specified file. This requires the ffmpeg binary to be (separately) installed—see the ffmpeg class documentation.

  • **kwargs – Additional keyword arguments are passed through to the constructor of the Recorder object (for example, to specify the device that should be used).

Examples:

import audiomath as am

s = am.Record()
# this records for up to 60 seconds (less if ctrl-C
# is pressed) and returns a `Sound` instance containing
# the recorded data.

s2 = am.Record(10, loop=True, filename='blah.mp3')
# this records indefinitely into a 10-second circular
# buffer, streaming the recorded data all the while into
# the file `blah.mp3`, and when you press ctrl-C it
# stops, cleans up, and returns the last 10 seconds as
# a `Sound` instance.
audiomath.Stack(*args)

Stack multiple Sound objects to make a new multi-channel Sound object (appending silence to the end of each argument where necessary to equalize lengths).

You can also stack channels of Sound instances using the & operator, and can modifying an existing Sound instance s (replacing its array s.y) using &=:

s = s1 & s2
s &= s1
audiomath.TestSound(*channels)

Return an 8-channel Sound object, read from a wav file that is bundled with audiomath, suitable for testing multi-channel sound output devices. Optionally, you can select particular channels using the same argument conventions as the IsolateChannels() method. For example, you could choose to return only the first two channels, as follows:

s = TestSound('12')
audiomath.ToneTest(freq=441, amplitude=0.1, nChannels=2, waveform=<function SineWave>, **kwargs)

This diagnostic test function creates a looped Player whose Sound is a 1-second pure tone, sampled at the preferred frequency of the Player (or the fs keyword argument passed through to it, if you want to specify that). Use an integer frequency freq to ensure glitch-free looping—any remaining glitches and crackles you hear when you Play() are likely the result of buffer underflows in the audio driver. This can happen if the same Python process that is driving the sound is also working too hard on other tasks: higher latencies protect against this.