The audiomath.PsychToolboxInterface
sub-module
This sub-module provides an alternative back-end for high-
precision playback, based on the PsychToolbox project’s reworking
of the PortAudio binaries. It requires the third-party
psychtoolbox
module to be installed (you must do this yourself,
for example by running python -m pip install psychtoolbox
,
because psychtoolbox
is not a hard/automatically-installed
dependency of audiomath
.
This alternative back-end can be enabled by calling
audiomath.BackEnd.Load('PsychToolboxInterface')
. This removes
the default audiomath.PortAudioInterface.*
symbols from the
top-level audiomath.*
namespace and replaces them with
audiomath.PsychToolboxInterface.*
symbols, most of which have
names and prototypes that are familiar from the default back-end
(Player
, Stream
, FindDevices
, etc…)
Extra features:
The
latencyClass
input parameter toPlayer
andStream
constructors. This is only respected for the first such construction call, since the sameStream
will be shared by allPlayer
instances). The supported settings are all attributes of theLATENCY_CLASS
enumerator. The higher the number, the more aggressively (and less cooperatively) the host API will drive the sound device, and the lower the latency is likely to get.The ability to pre-schedule sounds with the
when
argument, e.g.now = Seconds(); p.Play(when=now + 0.5)
Limitations, relative the the default PortAudioInterface
:
Player
objects cannotSeek(t)
to any position except the beginningt=0
(likewisePlay(t)
,Pause(t)
orSet(head=t)
will only work ift
is 0)no on-the-fly resampling or
speed
controlno dynamic properties
no on-the-fly sound synthesis (
Synth
data get frozen and truncated to 10 seconds when passed into aPlayer
).no
Recorder
implementation
Notes
on Windows, PsychToolbox uses the WASAPI host API by default. For best performance, and especially if you want to use
latencyClass < 2
(such that other processes can access the sound device at the same time) then you should ensure your sounds are sampled at 48000 Hz, not the usual 44100 Hz.some host APIs may be unable to be driven with certain latency classes (for example, on Windows most of the soundcard drivers we have tried cannot use WDM-KS with a latency class higher than 1)
- audiomath.PsychToolboxInterface.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.PsychToolboxInterface.FindDevices(id=None, mode=None, apiPreferences=None, _candidates=None)
Calls
GetDeviceInfo()
, filtering and reordering the outputs according to the specified criteria. You canprint()
the result, or otherwise convert it tostr()
, 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 whoseindex
field matchesid
;dict
(including the objects returned by this function, which aredict
subclassses): matches only the device whoseindex
field matchesid['index']
str
: matches any device with the specified word or phrase in itsname
field (you can also matchhostApi.name
andname
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 ofPORTAUDIO.DEFAULT_INPUT_API_PREFERENCE_ORDER
(if themode
argument requests any inputs) orPORTAUDIO.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.PsychToolboxInterface.GetDeviceInfo()
Returns a list of records corresponding to PortAudio’s
Pa_GetDeviceInfo()
output for every available combination of host API and device. You canprint()
the result, or otherwise convert it tostr()
, to see a pretty tabulated summary.
- audiomath.PsychToolboxInterface.GetHostApiInfo()
Returns a list of records corresponding to PortAudio’s
Pa_GetHostApiInfo()
output for every available host API. You canprint()
the result, or otherwise convert it tostr()
, to see a pretty tabulated summary.
- class audiomath.PsychToolboxInterface.LATENCY_CLASS
This class is an enum container: a namespace of values that can be passed as the
latencyClass
constructor argument when creating aPsychToolboxInterface.Player
instance.RELAXED
(0):indicates that latency is not a priority—latencies are then unpredictable and may be in the hundreds of milliseconds.
SHARED
(1):applies the most aggressive latency settings that still allow other processes to play sound at the same time.
EXCLUSIVE
(2):takes exclusive control of the sound card.
AGGRESSIVE
(3):takes exclusive control of the sound card, with even more aggressive low-latency settings than EXCLUSIVE mode.
CRITICAL
(4):is the same as AGGRESSIVE mode, but raises an exception if the settings cannot be achieved.
- class audiomath.PsychToolboxInterface.Player(sound, device=None, stream=None, latencyClass='DEFAULT', bufferLengthMsec=None, minLatencyMsec=None, fs=None, resample=True, verbose=None, **kwargs)
A
Player
provides a persistent connection to the chosen playback hardware, allowing aSound
instance to be played.A
Player
instance can only play oneSound
at a time, but it can optionally maintain a list ofSound
instances in aQueue
and switch between them. For overlapping sounds, use multiplePlayer
instances.A
Player
instance can be created directly from a filename, list of filenames or filename glob pattern. The currentSound
instance is available in thesound
property and the completeQueue
is available in thequeue
property.It is better to create a
Player
instance than to rely on the quick-and-dirtyPlay()
methods of theSound
andQueue
classes—these methods just create aPlayer
(entailing some computational overhead), wait synchronously for it to finish, and then destroy it again. Creating your ownPlayer
instance provides much greater flexibility and performance.- Parameters:
sound (str, Sound, Queue, None) –
Sound
instance to play (or sequence ofSound
instances in alist
orQueue
). Alternatively, supply any argument that is also a valid input to theSound
orQueue
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-openStream
instance.stream (int, str, dict, Stream, None) – Synonymous with
device
, for compatibility.latencyClass (int, str) – specify the PsychPortAudio latency mode (use one of the names or integer values defined in the enumerator
LATENCY_CLASS
)bufferLengthMsec (float, None) – Optionally specify a buffer length in milliseconds when creating your first
Player
or firstStream
. (FuturePlayer
instances will all use the same setting.)minLatencyMsec (float, None, ‘auto’) – Optionally specify the value to use as “suggested latency” when creating your first
Player
or firstStream
. (FuturePlayer
instances will all use the same setting.)fs (float, None) – Optionally specify the sampling frequency, in Hz, when creating your first
Player
or firstStream
(after that,Player
instances may share an openStream
instance so it is possible that only the first call will make any difference).resample (bool) – This should be left as
True
because there is no on-the-fly resampling capability in thePsychToolboxInterface
back-end, The parameter is included purely for compatibility with code written for the defaultPortAudioInterface
back-end.verbose (bool, None) – Verbosity for debugging. If
None
, inherit from the setting specified bySetDefaultVerbosity()
, if any.**kwargs – passed through to
Set()
to initialize properties of thePlayer
instance.
- property levels
This is an optional sequence of multipliers applied to each channel in turn. It is independent of (i.e. its effects simply get multiplied by the effects of) other properties that affect intensity, such as
volume
andpan
- property muted
This is a boolean property that, if true, causes the
Player
to be silent, independent of the currentvolume
and/orlevels
.
- property norm
For a
Player
instancep
, if you setp.pan
to a scalar value between -1 and +1, the relative levels of left and right channels are computed such that:left ** p.norm + right ** p.norm = 1
The value
p.norm=2
produces a natural-sounding pan but it means that stereo sounds are reduced to 70.71% of their maximum amplitude by default. So instead, the default is to use the infinity-norm,p.norm='inf'
, which ensures that the larger of the two sides is always 1.0
- property pan
A value of -1 means left channels only, right channels silent. A value of 0 means left and right channels at equal volume. A value of +1 means right channels only, left channels silent.
The way levels are computed from scalar values between -1 and +1 depends on
norm
. Alternatively, you can supply a two- element sequence that explicitly specifies[left, right]
levels.Note that these levels are independent from (i.e. they are simply multiplied by) the overall
volume
and channel-by- channellevels
settings.
- property sound
A reference to the
Sound
instance that thePlayer
is currently playing, orNone
. You can change it on-the-fly. It may also change automatically when the current sound finishes playing, if you have appended additionalSound
instances thequeue
and have set theautoAdvance
property.
- property vol
This floating-point property is a multiplier for the amplitude of the sound waveforms. It is independent of (i.e. its effect simply gets multiplied by the effects of) other properties that affect channel-to- channel level differences, such as
levels
andpan
- audiomath.PsychToolboxInterface.Record(*p, **k)
TODO: no
Record()
implementation yet in this back-end
- class audiomath.PsychToolboxInterface.Recorder(*p, **k)
TODO: no
Recorder
implementation yet in theaudiomath.PsychToolboxInterface
back-end
- audiomath.PsychToolboxInterface.Seconds()
An alias for PsychToolbox’s clock,
psychtoolbox.GetSecs()
- class audiomath.PsychToolboxInterface.Stream(device=(), mode=None, sampleRate=None, latencyClass='DEFAULT', verbose=False, 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 ownStream
.Typically, objects that play or record will automatically create a
Stream
or add themselves to an existingStream
, so you will not usually need to construct aStream
instance yourself. The exception is when you need to ensure that the construction of such objects is itself fast: then, creating aStream
in advance, and keeping a reference to it to use in initializing the other objects, will speed things up.The
device
,mode
andapiPreferences
arguments are the same asid
,mode
andapiPreferences
inFindDevice()
.The
latencyClass
argument is unique to thePsychToolboxInterface
back-end. It specifies the PsychPortAudio latency mode (use one of the names or integer values defined in the enumeratorLATENCY_CLASS
).