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
latencyClassinput parameter toPlayerandStreamconstructors. This is only respected for the first such construction call, since the sameStreamwill be shared by allPlayerinstances). The supported settings are all attributes of theLATENCY_CLASSenumerator. 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
whenargument, e.g.now = Seconds(); p.Play(when=now + 0.5)
Limitations, relative the the default PortAudioInterface:
Playerobjects cannotSeek(t)to any position except the beginningt=0(likewisePlay(t),Pause(t)orSet(head=t)will only work iftis 0)no on-the-fly resampling or
speedcontrolno dynamic properties
no on-the-fly sound synthesis (
Synthdata get frozen and truncated to 10 seconds when passed into aPlayer).no
Recorderimplementation
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 whoseindexfield matchesid;dict(including the objects returned by this function, which aredictsubclassses): matches only the device whoseindexfield matchesid['index']str: matches any device with the specified word or phrase in itsnamefield (you can also matchhostApi.nameandnamesimultaneously 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 themodeargument requests any inputs) orPORTAUDIO.DEFAULT_OUTPUT_API_PREFERENCE_ORDERotherwise. 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
latencyClassconstructor argument when creating aPsychToolboxInterface.Playerinstance.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
Playerprovides a persistent connection to the chosen playback hardware, allowing aSoundinstance to be played.A
Playerinstance can only play oneSoundat a time, but it can optionally maintain a list ofSoundinstances in aQueueand switch between them. For overlapping sounds, use multiplePlayerinstances.A
Playerinstance can be created directly from a filename, list of filenames or filename glob pattern. The currentSoundinstance is available in thesoundproperty and the completeQueueis available in thequeueproperty.It is better to create a
Playerinstance than to rely on the quick-and-dirtyPlay()methods of theSoundandQueueclasses—these methods just create aPlayer(entailing some computational overhead), wait synchronously for it to finish, and then destroy it again. Creating your ownPlayerinstance provides much greater flexibility and performance.- Parameters:
sound (str, Sound, Queue, None) –
Soundinstance to play (or sequence ofSoundinstances in alistorQueue). Alternatively, supply any argument that is also a valid input to theSoundorQueueconstructors (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-openStreaminstance.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
Playeror firstStream. (FuturePlayerinstances will all use the same setting.)minLatencyMsec (float, None, ‘auto’) – Optionally specify the value to use as “suggested latency” when creating your first
Playeror firstStream. (FuturePlayerinstances will all use the same setting.)fs (float, None) – Optionally specify the sampling frequency, in Hz, when creating your first
Playeror firstStream(after that,Playerinstances may share an openStreaminstance so it is possible that only the first call will make any difference).resample (bool) – This should be left as
Truebecause there is no on-the-fly resampling capability in thePsychToolboxInterfaceback-end, The parameter is included purely for compatibility with code written for the defaultPortAudioInterfaceback-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 thePlayerinstance.
- 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
volumeandpan
- property muted
This is a boolean property that, if true, causes the
Playerto be silent, independent of the currentvolumeand/orlevels.
- property norm
For a
Playerinstancep, if you setp.panto 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=2produces 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
volumeand channel-by- channellevelssettings.
- property sound
A reference to the
Soundinstance that thePlayeris 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 additionalSoundinstances thequeueand have set theautoAdvanceproperty.
- 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
levelsandpan
- audiomath.PsychToolboxInterface.Record(*p, **k)
TODO: no
Record()implementation yet in this back-end
- class audiomath.PsychToolboxInterface.Recorder(*p, **k)
TODO: no
Recorderimplementation yet in theaudiomath.PsychToolboxInterfaceback-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
Streamor add themselves to an existingStream, so you will not usually need to construct aStreaminstance yourself. The exception is when you need to ensure that the construction of such objects is itself fast: then, creating aStreamin advance, and keeping a reference to it to use in initializing the other objects, will speed things up.The
device,modeandapiPreferencesarguments are the same asid,modeandapiPreferencesinFindDevice().The
latencyClassargument is unique to thePsychToolboxInterfaceback-end. It specifies the PsychPortAudio latency mode (use one of the names or integer values defined in the enumeratorLATENCY_CLASS).