The audiomath.PortAudioInterface sub-module

This submodule contains PortAudio-specific implementations of high- level Player and Recorder classes. They inherit their API-user- facing functionality, as well as their code for manipulating raw Sound data, from GenericInterface.GenericPlayer and GenericInterface.GenericRecorder. The PortAudio-specific subclasses act as intermediaries between the generic stuff and the objects and functions in the _wrap_portaudio submodule.

This submodule also contains various global functions for listing and selecting the available sound devices and their host APIs.

The PortAudioInterface is the default playing/recording back-end for audiomath. Therefore, all the symbols exported by this submodule are also available at the top level audiomath.* namespace (at least until another back-end is written, and loaded with audiomath.BackEnd.Load()).

audiomath.PortAudioInterface.FindDevice(id=None, mode=None, apiPreferences=None, _candidates=None)

Returns the first device matched by FindDevices() (plural) according to the specified criteria. Raises an exception if there are no matches.

audiomath.PortAudioInterface.FindDevices(id=None, mode=None, apiPreferences=None, _candidates=None)

Calls GetDeviceInfo(), filtering and reordering the outputs according to the specified criteria. You can print() the result, or otherwise convert it to str(), to see a pretty tabulated summary.

You can use FindDevice() (singular) to return just the top-ranking result (and to assert that at least one result can be found).

Parameters:
  • id (int, dict, str, None) –

    • None: matches all devices;

    • int: matches only the device whose index field matches id;

    • dict (including the objects returned by this function, which are dict subclassses): matches only the device whose index field matches id['index']

    • str: matches any device with the specified word or phrase in its name field (you can also match hostApi.name and name simultaneously if you delimit them with '//'—for example, 'WDM-KS//Speakers');

  • mode (str, tuple, None) – May be either a two-element tuple such as mode=(minInputChannels,minOutputChannels), or a string containing a number of 'o' and/or 'i' characters. In either case, devices are only matched if they provide at least the specified number of input and output channels. For example, FindDevices(mode='oo') matches all devices that provide two or more output channels.

  • apiPreferences (str, None) – If this is left at None, it defaults to the current value of PORTAUDIO.DEFAULT_INPUT_API_PREFERENCE_ORDER (if the mode argument requests any inputs) or PORTAUDIO.DEFAULT_OUTPUT_API_PREFERENCE_ORDER otherwise. The string '*' matches all host APIs. Host APIs may be comma-delimited. For example, apiPreferences='DirectSound,*' means “give first priority to devices hosted by the DirectSound API, and then, failing that, match all other APIs”. If '*' is not included in the specification, this argument may limit the number of records returned. In any case it will affect the ordering of the returned records.

audiomath.PortAudioInterface.GetDeviceInfo()

Returns a list of records corresponding to PortAudio’s Pa_GetDeviceInfo() output for every available combination of host API and device. You can print() the result, or otherwise convert it to str(), to see a pretty tabulated summary.

audiomath.PortAudioInterface.GetHostApiInfo()

Returns a list of records corresponding to PortAudio’s Pa_GetHostApiInfo() output for every available host API. You can print() the result, or otherwise convert it to str(), to see a pretty tabulated summary.

audiomath.PortAudioInterface.GetInputDevice()

Return the default input device, if any has been set.

See also: SetInputDevice()

audiomath.PortAudioInterface.GetOutputDevice()

Return the default output device, if any has been set.

See also: SetOutputDevice()

audiomath.PortAudioInterface.LowLatencyMode(turnOn, preferASIO=False)

Call this function before you create your first Stream or Player instance.

On Windows, LowLatencyMode(True) will manipulate PORTAUDIO.DEFAULT_OUTPUT_API_PREFERENCE_ORDER to cause the WDM-KS host API (or the ASIO host API, if preferASIO is True) to be preferred over DirectSound when constructing output streams. This will allow considerably lower output latencies, but will have the side-effect of taking exclusive control of the sound driver, meaning that sounds from other applications will no longer be audible (this may or may not be desirable, depending on your application).

LowLatencyMode(True) also sets PORTAUDIO.DEFAULT_BUFFER_LENGTH_MSEC = None, and PORTAUDIO.DEFAULT_MIN_LATENCY_MSEC = 4, which will have the effect of lowering latencies but at the cost of making sounds vulnerable to stuttering if Python performs any significant work during playback.

LowLatencyMode(False) reverts to factory settings (DirectSound is reinstated as the preferred host API on Windows, and PORTAUDIO.DEFAULT_MIN_LATENCY_MSEC is set to 'auto' (which means 60 for DirectSound and at least 10 elsewhere) for future Stream instances.

class audiomath.PortAudioInterface.Player(sound, device=None, stream=None, bufferLengthMsec=None, minLatencyMsec=None, fs=None, resample=False, verbose=None, **kwargs)

A Player provides a persistent connection to the chosen playback hardware, allowing a Sound instance to be played.

A Player instance can only play one Sound at a time, but it can optionally maintain a list of Sound instances in a Queue and switch between them. For overlapping sounds, use multiple Player instances.

A Player instance can be created directly from a filename, list of filenames or filename glob pattern. The current Sound instance is available in the sound property and the complete Queue is available in the queue property.

It is better to create a Player instance than to rely on the quick-and-dirty Play() methods of the Sound and Queue classes—these methods just create a Player (entailing some computational overhead), wait synchronously for it to finish, and then destroy it again. Creating your own Player instance provides much greater flexibility and performance.

Parameters:
  • sound (str, Sound, Queue, None) – Sound instance to play (or sequence of Sound instances in a list or Queue). Alternatively, supply any argument that is also a valid input to the Sound or Queue constructors (e.g. a filename, list of filenames, or file glob pattern).

  • device (int, str, dict, Stream, None) – Optionally use this argument to specify the device/stream to use for playback—as an integer index, a device name, a full device record from FindDevice(), or (fastest of all) an already-open Stream instance.

  • stream (int, str, dict, Stream, None) – Synonymous with device, for compatibility.

  • bufferLengthMsec (float, None, ‘auto’) – Optionally specify a buffer length in milliseconds when creating your first Player or first Stream (after that, Player instances may share an open Stream instance so it is possible that only the first call will make any difference). Larger buffer lengths lead to higher playback latencies. None means use whatever is currently globally configured in PORTAUDIO.DEFAULT_BUFFER_LENGTH_MSEC. 'auto' or 'pa-default' means use the default supplied by the PortAudio library.

  • minLatencyMsec (float, None, ‘auto’) – Use this setting to override the PortAudio default for “suggested” latency when creating a Stream. The values supplied here typically undershoot the empirically measurable latency (in a non-linear fashion) but larger values mean greater robustness (less crackle/stutter susceptibility) at the cost of longer latencies and higher jitter. None means use whatever is currently globally configured in PORTAUDIO.DEFAULT_MIN_LATENCY_MSEC. 'auto' means use certain defaults that we have empirically derived to balance these factors. 'pa-default' means use the defaults supplied by the PortAudio library.

  • fs (float, None) – Optionally specify the sampling frequency, in Hz, when creating your first Player or first Stream (after that, Player instances may share an open Stream instance so it is possible that only the first call will make any difference).

  • resample (bool) – Specifies how to handle potential mismatch between the sampling frequency of the sound data self.sound.fs and the sampling frequency of the output stream self.stream.fs. If true, replace self.sound with a copy resampled to the stream’s preferred rate. If false, simply adjust playback speed accordingly (at a small, ongoing, computational cost).

  • verbose (bool, None) – Verbosity for debugging. If None, inherit from the setting specified by SetDefaultVerbosity(), if any.

  • **kwargs – passed through to Set() to initialize properties of the Player instance.

audiomath.PortAudioInterface.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.
class audiomath.PortAudioInterface.Recorder(seconds, device=None, stream=None, bufferLengthMsec=None, minLatencyMsec=None, fs=None, start=True, loop=False, verbose=None, filename=None, **kwargs)

A Recorder provides a persistent connection to the chosen recording hardware, allowing sound to be recorded into a Sound instance.

You may find it more useful to use the global function Record, which synchronously records and returns a Sound instance, than to create or interact directly with Recorder instances. However, Recorder instances are the way to go if you want to record asynchronously, in the background.

Parameters:
  • seconds (float, Sound) – number of seconds to pre-allocate for recording, or an already-pre-allocated Sound instance into which to record

  • device (int, str, dict, Stream) – specification of the device/stream to use for recording (as an index, name, full device record from FindDevice(), or already-open Stream instance)

  • stream (int, str, dict, Stream) – synonymous with device, for compatibility

  • fs (float, None) – Optionally specify the sampling frequency, in Hz, when creating your first Recorder or first Stream (after that, Recorder instances may share an open Stream instance so it is possible that only the first call will make any difference).

  • start (bool) – whether to start recording immediately

  • loop (bool) – whether to record indefinitely, treating self.sound as a circular buffer, or simply stop when the capacity of self.sound is reached

  • verbose (bool, None) – verbosity for debugging. If None, inherit from the setting specified by SetDefaultVerbosity(), if any

  • **kwargs – passed through to Set() to initialize properties of the Recorder instance.

audiomath.PortAudioInterface.Seconds()

A platform-dependent high-precision clock. Origin (time zero) is arbitrary, but fixed within a given Python session.

audiomath.PortAudioInterface.SetDefaultVerbosity(value)

Useful for debugging when the PortAudio library is initialized or terminated, when streams are opened, started, stopped or closed, and when other objects such as players or recorders are initialized or garbage-collected. Objects may be individually marked as verbose=True or verbose=False, but by default they inherit their verbosity from the setting you specify here.

audiomath.PortAudioInterface.SetInputDevice(device)

Set the specified device as the default device to be used for Recorder objects. The device argument may be the device index, one or more words from the device name, or the full device record from GetDeviceInfo() or FindDevices().

See also: GetInputDevice()

audiomath.PortAudioInterface.SetOutputDevice(device)

Set the specified device as the default device to be used for Player objects. The device argument may be the device index, one or more words from the device name, or the full device record from GetDeviceInfo() or FindDevices().

Note that, by default, Player instances share a single Stream instance—this means that the preference you specify here (and the preference you specify in the Player constructor) may not be honored if there are already other Player instances in existence (and hence an already-running Stream). In short: it’s best to use this function before you construct your first Player or Stream instance.

See also: GetOutputDevice()

class audiomath.PortAudioInterface.Stream(device=None, mode=None, apiPreferences=None, outputCallbacks=None, sampleRate=None, sampleFormat=None, verbose=None, bufferLengthMsec=None, minLatencyMsec=None)

A persistent connection to an audio driver. Multiple output callbacks (player objects) and/or multiple input callbacks (recorder objects) may share the same Stream, or under some conditions it may be possible for each callback (or object) to have its own Stream.

Typically, objects that play or record will automatically create a Stream or add themselves to an existing Stream, so you will not usually need to construct a Stream instance yourself. The exception is when you need to ensure that the construction of such objects is itself fast: then, creating a Stream in advance, and keeping a reference to it to use in initializing the other objects, will speed things up.

The device, mode and apiPreferences arguments are the same as id, mode and apiPreferences in FindDevice().

audiomath.PortAudioInterface.Tabulate(records, *fields)

Returns a pretty-printed table of the specified fields (i.e. dictionary entries or attributes) of a list of records. This is called automatically, with certain default combinations of field names, when you print() the results of GetHostApiInfo(), GetDeviceInfo() or FindDevices().