.. _soundPlayback:

:class:`Sound` - for audio playback
-----------------------------------

.. module:: psychopy.sound
.. currentmodule:: psychopy.sound

Audio playback is handled by the :class:`Sound` class. |PsychoPy| currently
supports a choice of sound engines: *PTB*, *pyo*, *sounddevice* or *pygame*. You
can select which will be used via the :ref:`audioLib<hardwareSettings>`
preference. `sound.Sound()` will then refer to one of the following backends:

* :class:`~psychopy.sound.backend_ptb.SoundPTB`
* :class:`~psychopy.sound.backend_sounddevice.SoundDevice`
* :class:`~psychopy.sound.backend_pyo.SoundPyo`
* :class:`~psychopy.sound.backend_pygame.SoundPygame`

This preference can be set on a per-experiment basis by importing preferences,
and :doc:`setting the audioLib option</api/preferences>` to use. Audio playback
backends vary in performance due to all sorts of factors. Based on testing done
by the |PsychoPy| team and reports from users, their performance can be summarized
as follows:

* The `PTB` library has by far the lowest latencies and is strongly recommended
  (requires 64 bit Python 3.6+)
* The `pyo` library is, in theory, the highest performer, but in practice it has
  often had issues (at least on MacOS) with crashes and freezing of experiments,
  or causing them not to finish properly. If those issues aren't affecting your
  studies then this could be the one for you.
* The `sounddevice` library has performance that appears to be good (although
  this might be less so in cases where you have complex rendering being done as
  well because it operates from the same computer core as the main experiment
  code). It's newer than `pyo` and so more prone to bugs and we haven't yet
  added microphone support to record your participants.
* The `pygame` backend is the oldest and should work without errors, but has the
  least good performance. Use it if latencies for your audio don't matter.

Sounds are actually generated by a variety of classes, depending on which
"backend" you use (like pyo or sounddevice) and these different backends can
have slightly different attributes, as below. The user should typically do::

    from psychopy.sound import Sound

The class that gets imported will then be an alias of one of the
:ref:`soundClasses` described below.


.. _PTB_audio_latency:

PTB audio latency
~~~~~~~~~~~~~~~~~

PTB brings a number of advantages in terms of latency.

The first is that is has
been designed specifically with low-latency playback in mind (rather than, say,
on-the-fly mixing and filtering capabilities). Mario Kleiner has worked very hard
get the best out of the drivers available on each operating system and, as a
result, with the most aggressive low-latency settings you can get a sound to
play in "immediate" mode with typically in the region of 5ms lag and maybe 1ms
precision. That's pretty good compared to the other options that have a lag of
20ms upwards and several ms variability.

BUT, on top of that, PTB allows you to :ref:`preschedule<ptbPreschedule>` your
sound to occur at a particular point in time (e.g. when the trigger is due to be
sent or when the screen is due to flip) and the PTB engine will then prepare all
the buffers ready to go and will also account for the known latencies in the
card. With this method the PTB engine is capable of sub-ms *precision* and even
sub-ms *lag*!

Of course, *capable* doesn't mean it's happening in your case. It can depend on
many things about the local operating system and hardware. You should test it
yourself for your kit, but here is an example of a standard Win10 box using
built-in audio (not a fancy audio card):

.. figure:: /images/audioScope_win10_PTB_mode3.png
    :align: center

    Sub-ms audio timing with standard audio on Win10. Yellow trace is a 440
    Hz tone played at 48 kHz with PTB engine. Cyan trace is the trigger
    (from a Labjack output). Gridlines are set to 1 ms.


.. _ptbPreschedule:

Preschedule your sound
~~~~~~~~~~~~~~~~~~~~~~

The most precise way to use the PTB audio backend is to preschedule the
playing of a sound. By doing this PTB can actually take into account both the
time taken to load the sound (it will preload ready) and also the time taken
by the hardware to start playing it.

To do this you can call `play()` with an argument called `when`. The `when`
argument needs to be in the PsychToolBox clock timebase which can be accessed by
using `psychtoolbox.GetSecs()` if you want to play sound at an arbitrary time
(not in sync with a window flip)

For instance::

    import psychtoolbox as ptb
    from psychopy import sound

    mySound = sound.Sound('A')
    now = ptb.GetSecs()
    mySound.play(when=now+0.5)  # play in EXACTLY 0.5s

or using `Window.getFutureFlipTime(clock='ptb')` if you want a
synchronized time::

    import psychtoolbox as ptb
    from psychopy import sound, visual

    mySound = sound.Sound('A')

    win = visual.Window()
    win.flip()
    nextFlip = win.getFutureFlipTime(clock='ptb')

    mySound.play(when=nextFlip)  # sync with screen refresh

The precision of that timing is still dependent on the :ref:`PTB_latency_modes`
and can obviously not work if the delay before the requested time is not long
enough for the requested mode (e.g. if you request that the sound starts on the
next refresh but set the latency mode to be `0` (which has a lag of around 300 ms)
then the timing will be very poor.

.. _PTB_latency_modes:

PTB Audio Latency Modes
~~~~~~~~~~~~~~~~~~~~~~~

When using the PTB backend you get the option to choose the Latency Mode,
referred to in PsychToolBox as the `reqlatencyclass`, and can be set in
PsychoPy using :ref:`prefs.hardware['audioLatencyMode'] <hardwareSettings>`.

|PsychoPy| uses Mode 3 in as a default, assuming that you want low latency and you
don't care if other applications can't play sound at the same time (don't listen
to iTunes while running your study!)

The modes are as follows:

**0 : Latency not important**
    For when it really doesn't matter. Latency can easily be in the region of
    300ms! The advantage of this move is that it will always work and always play a sound,
    whatever the format of the existing sounds that have been played (with 2, 3, 4 you can obtain low latency but the
    sampling rate must be the same throughout the experiment).

**1 : Share low-latency access**
    Tries to use a low-latency setup in combination
    with other applications. Latency usually isn't very good and in MS Windows
    the sound you play must be the same sample rate as any other application
    that is using the sound system (which means you usually get restricted to
    exactly 48000 instead of 44100).

**2 : Exclusive mode low-latency**
    Takes control of the audio device you're using and dominates it. That can
    cause some problems for other apps if they're trying to play sounds at the
    same time.

**3 : Aggressive exclusive mode**
    As Mode 2 but with more aggressive settings to prioritise our use of the
    card over all others. **This is the recommended mode for most studies**

**4 : Critical mode**
    As Mode 3 except that, if we fail to be totally dominant, then raise an
    error rather than just accepting our slightly less dominant status.

.. _PTB_devices:

PTB Devices
~~~~~~~~~~~

To set the output audio device to use, you can set the
:ref:`prefs.hardware['audioDevice'] <hardwareSettings>` setting. To determine
the set of available devices, you can do for example::

        from pprint import pprint
        import psychtoolbox.audio
        pprint(psychtoolbox.audio.get_devices())

.. _soundClasses:

Sound Classes
=============

`PTB` Sound
~~~~~~~~~~~

.. autoclass:: psychopy.sound.backend_ptb.SoundPTB
    :members:


`SoundDevice` Sound
~~~~~~~~~~~~~~~~~~~

.. autoclass:: psychopy.sound.backend_sounddevice.SoundDeviceSound
    :members:

`Pyo` Sound
~~~~~~~~~~~

.. autoclass:: psychopy.sound.backend_pyo.SoundPyo
    :members:


`pygame` Sound
~~~~~~~~~~~~~~

.. autoclass:: psychopy.sound.backend_pygame.SoundPygame
    :members:
