Skip to content

exclusive mode for wasapi #35

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
piotx opened this issue Aug 16, 2016 · 70 comments
Closed

exclusive mode for wasapi #35

piotx opened this issue Aug 16, 2016 · 70 comments

Comments

@piotx
Copy link

piotx commented Aug 16, 2016

Hello,

it's not an issue, but rather a question.

Is it possible to enable exclusive for wasapi?

best wishes
Piotr

@mgeier
Copy link
Member

mgeier commented Aug 16, 2016 via email

@piotx
Copy link
Author

piotx commented Aug 16, 2016

yes, I would love to test it. The wasapi exclusive mode is supposed to have
low latency and I would like to test this with an oscilloscope...

2016-08-16 19:47 GMT+02:00 Matthias Geier [email protected]:

Not yet. But if you are willing to test it, I can try to implement it.


You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
#35 (comment),
or mute the thread
https://github.com/notifications/unsubscribe-auth/ANHZpp2NXvKtH4-jCBFBdgviFa41N7gkks5qgfekgaJpZM4Jk5TB
.

@mgeier
Copy link
Member

mgeier commented Aug 17, 2016

Great! I'll implement this next week and let you know when there's something
to test.

@mgeier
Copy link
Member

mgeier commented Aug 25, 2016

See also #4.

mgeier added a commit that referenced this issue Aug 26, 2016
@mgeier
Copy link
Member

mgeier commented Aug 26, 2016

@piotx I've implemented this in #39. Can you please check if it works?

@piotx
Copy link
Author

piotx commented Aug 26, 2016

I've installed the wasapi-settings branch, but get the following error,
when running wasapi_exclusive = sd.WasapiSettings(exclusive=True):

c:\python27\lib\site-packages\sounddevice-0.3.4-py2.7.egg\sounddevice.pyc
in **i
nit**(self, exclusive)
   2321         flags = 0x0
   2322         if exclusive:
-> 2323             flags |= paWinWasapiExclusive
   2324         self._streaminfo = _ffi.new('PaWasapiStreamInfo*', dict(
   2325             size=_ffi.sizeof('PaWasapiStreamInfo'),

NameError: global name 'paWinWasapiExclusive' is not defined

I have no experience with cffi and don't know how to fix it.

@mgeier
Copy link
Member

mgeier commented Aug 26, 2016

Sorry, my bad!

I've updated the last commit, can you please try again?

@piotx
Copy link
Author

piotx commented Aug 26, 2016

so I got:

In [9]: sd.default.extra_settings = wasapi_exclusive
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-9-5cc895cc08f4> in <module>()
----> 1 sd.default.extra_settings = wasapi_exclusive

c:\python27\lib\site-packages\sounddevice-0.3.4-py2.7.egg\sounddevice.pyc in __s
etattr__(self, name, value)
   2175     def __setattr__(self, name, value):
   2176         """Only allow setting existing attributes."""
-> 2177         if name in _pairs:
   2178             getattr(self, name)._pair[:] = _split(value)
   2179         elif name in dir(self) and name != 'reset':

NameError: global name '_pairs' is not defined

@mgeier
Copy link
Member

mgeier commented Aug 26, 2016

Silly me. I made another mistake. Can you try again, please?

@piotx
Copy link
Author

piotx commented Aug 26, 2016

mhm.. I tried also to change _pairs to self._pairs but the first error is
still there..

  File "wasapi_test.py", line 9, in <module>
    sd.play(data, fs, device = 9)
  File
"C:\Python27\lib\site-packages\sounddevice-0.3.4-py2.7.egg\sounddevice.py
", line 387, in play
    *_kwargs)
  File
"C:\Python27\lib\site-packages\sounddevice-0.3.4-py2.7.egg\sounddevice.py
", line 2461, in start_stream
    *_kwargs)
  File
"C:\Python27\lib\site-packages\sounddevice-0.3.4-py2.7.egg\sounddevice.py
", line 1540, in **init**
    prime_output_buffers_using_stream_callback)
  File
"C:\Python27\lib\site-packages\sounddevice-0.3.4-py2.7.egg\sounddevice.py
", line 911, in **init**
    'Error opening {0}'.format(self.**class**.**name**))
  File
"C:\Python27\lib\site-packages\sounddevice-0.3.4-py2.7.egg\sounddevice.py
", line 2598, in _check
    raise PortAudioError(msg)
sounddevice.PortAudioError: Error opening OutputStream: Incompatible hostAPI specific stream info

@piotx
Copy link
Author

piotx commented Aug 26, 2016

but actually wasapi just doesn't work anymore at all. I had this behavior before, but I really don't understand it; no idea, why. I'll test it on the pc

@piotx
Copy link
Author

piotx commented Aug 26, 2016

on win8, I get the same error as before:

Traceback (most recent call last):
  File "sd2.py", line 11, in <module>
    sd.play(data, fs, device=14)
  File "C:\Python27\lib\site-packages\sounddevice-0.3.4-py2.7.egg\sounddevice.py
", line 385, in play
    **kwargs)
  File "C:\Python27\lib\site-packages\sounddevice-0.3.4-py2.7.egg\sounddevice.py
", line 2459, in start_stream
    **kwargs)
  File "C:\Python27\lib\site-packages\sounddevice-0.3.4-py2.7.egg\sounddevice.py
", line 1538, in __init__
    prime_output_buffers_using_stream_callback)
  File "C:\Python27\lib\site-packages\sounddevice-0.3.4-py2.7.egg\sounddevice.py
", line 909, in __init__
    'Error opening {0}'.format(self.__class__.__name__))
  File "C:\Python27\lib\site-packages\sounddevice-0.3.4-py2.7.egg\sounddevice.py
", line 2596, in _check
    raise PortAudioError(msg)
sounddevice.PortAudioError: Error opening OutputStream: Incompatible host API sp
ecific stream info

@piotx
Copy link
Author

piotx commented Aug 26, 2016

and on my laptop wasapi juest doesn't work anymore, it says invalid device, although I'm using the same device, same drivers etc.. wdm/ks still works; that's so strange..

@mgeier
Copy link
Member

mgeier commented Aug 27, 2016

OK, I guess now we are down to the real problem ...

Please make sure that you are using the correct DLL, see #36 (comment).

You could also try the DLL from https://github.com/adfernandes/precompiled-portaudio-windows instead of the bundled DLL. Or the one from pyo.

Can you please try it with WasapiSettings(exclusive=False)?

Probably the error is related to hostApiType. It's supposed to be paWASAPI, which stands for the number 13, but you could try other numbers from 0 to 14.

On the computers where WASAPI doesn't work, does it work with other PortAudio applications, e.g. Audacity?

@piotx
Copy link
Author

piotx commented Aug 27, 2016

yes, I'm using the correct dll (I need to specify it each time in
sounddevice.py, otherwise some other version of portaudio is loaded, which
has only 5 devices (mme and wasapi hosts); I don't know where it is
located, it's not the pyo one, because I have uninstalled pyo beforehand);

I'm using windows 7 on my laptop. The wasapi drivers worked with
sounddevice before on this machine, now they don't. I get the same error
with Fernandes' dlls; Now I tried it out with pyo and get the same error as
in sounddevice.

Loopback recording with wasapi host under audacity however works well on
the same machine. So maybe it's something python specific.. I don't know

@mgeier
Copy link
Member

mgeier commented Aug 28, 2016

I don't know why WASAPI doesn't work anymore. Did you try an older version of python-sounddevice for comparison?

You could search your hard disk for portaudio.dll to find out where the unwanted DLL is located.

@piotx
Copy link
Author

piotx commented Aug 28, 2016

ok, when I run wasapi_exclusive = sd.WasapiSettings(exclusive=False), I get
the same error, as with exclusive = True on win8:

sounddevice.PortAudioError: Error opening OutputStream: Incompatible host
API sp
ecific stream info

same error with Fernandes' libraries

@piotx
Copy link
Author

piotx commented Aug 28, 2016

ok, I've tried to set hostApiType in the WasapiSettings class to any number
from 0 to 14, but got the same error. Is there an easy way to access
self._streaminfo to print the hostApiType?

@mgeier
Copy link
Member

mgeier commented Aug 28, 2016

This should do it:

wasapi_exclusive._streaminfo.hostApiType

If you want to get the host API type from an existing stream, you'll need Pa_GetStreamHostApiType, which isn't implemented in python-sounddevice.

You can add this to the cdef() string:

PaHostApiTypeId Pa_GetStreamHostApiType( PaStream* stream );

And then you should be able to use it like this:

mystream = sd.OutputStream(...)
ha_type = sd._lib.Pa_GetStreamHostApiType(mystream._ptr)

@mgeier mgeier closed this as completed in 3827d2e Aug 28, 2016
@mgeier
Copy link
Member

mgeier commented Aug 28, 2016

I've merged #39 into master to make it easier for others to try out the extra WASAPI settings.

For your convenience, I've also added the C definition mentioned above, see eaede7f.

@mgeier mgeier reopened this Aug 28, 2016
@piotx
Copy link
Author

piotx commented Aug 31, 2016

regarding wasapi not working, I've tried it out with pysounddevice and it didn't work...

the portaudio.dll on the win8 was actually located in the psychopy folder (c:\programfiles (x86)\psychopy), I didn't expect cffi to search there... Maybe the path was added to my local python installation...

@mgeier
Copy link
Member

mgeier commented Oct 17, 2016

@piotx Any news? Did you get it to work in the meantime?

@piotx
Copy link
Author

piotx commented Oct 25, 2016

Hello Matthias,

I didn't try it out any more, I would linke to do it again after
reinstallinh Windows..

@stfnrpplngr
Copy link

Hello,

on a Windows 7 system, I get the same error message as Piotr.

import sounddevice as sd
sd.default.device = 10
wasapi_exclusive = sd.WasapiSettings(exclusive=True)
sd.default.extra_settings = wasapi_exclusive
sd.play(sound1)
Traceback (most recent call last):
  File "<input>", line 1, in <module>
  File "C:\Program Files (x86)\Anaconda2\Lib\site-packages\sounddevice.py", line 392, in play
    **kwargs)
  File "C:\Program Files (x86)\Anaconda2\Lib\site-packages\sounddevice.py", line 2466, in start_stream
    **kwargs)
  File "C:\Program Files (x86)\Anaconda2\Lib\site-packages\sounddevice.py", line 1545, in __init__
    prime_output_buffers_using_stream_callback)
  File "C:\Program Files (x86)\Anaconda2\Lib\site-packages\sounddevice.py", line 916, in __init__
    'Error opening {0}'.format(self.__class__.__name__))
  File "C:\Program Files (x86)\Anaconda2\Lib\site-packages\sounddevice.py", line 2603, in _check
    raise PortAudioError(msg)
PortAudioError: Error opening OutputStream: Incompatible host API specific stream info

Cheers
Stefan

@hiccup7
Copy link

hiccup7 commented Nov 21, 2016

sd.get_portaudio_version() returns a string beginning with 1899 using the DLL bundled in sounddevice. If I understand correctly, 1899 is the SVN revision from the PortAudio repository. I looked here today:
https://app.assembla.com/spaces/portaudio/subversion/commits/list
I see that PortAudio is now up to SVN revision 1968. Revisions 1961-1963 had to do with WASAPI.
Want to try updating the DLLs bundled in sounddevice? I volunteer to test.

@mgeier
Copy link
Member

mgeier commented Nov 21, 2016

Good idea! Actually, I was already working on updating to the new PortAudio release, some testing would be very welcome!

For now, there is a branch called portaudio-19.6.0-win including the new DLLs. Would be great if you could check it out!

@hiccup7
Copy link

hiccup7 commented Nov 21, 2016

I would like to download files from GitHub manually. Can I just replace libportaudio64bit.dll and sounddevice.py in my present sounddevice installation in WinPython with the files from the portaudio-19.6.0-win branch?

@mgeier
Copy link
Member

mgeier commented Nov 21, 2016

Yes, this should work, too.
You don't even need sounddevice.py, the DLL should be enough.

@cosacog
Copy link

cosacog commented Nov 22, 2016

Thank you mgeier. I installed new DLL and played without error.

wasapi_exclusive = sd.WasapiSettings(exclusive=True)
sd.play(mysnd, extra_settings=wasapi_exclusive)

I will report the performance aftertime.

@piotx
Copy link
Author

piotx commented Nov 22, 2016

I've just checked it out on win8 and it works for me as well! Pretty cool!
I'll test the latency with an oscilloscope...

@piotx
Copy link
Author

piotx commented Nov 22, 2016

ok, so wasapi (exclusive=True) works with sd.play. that's pretty cool! The latency seems to be great (as measured with an oscilloscope and parallel port triggers), but only 37ms of the 50ms sound are played back on one of my machines (win8 with onboard soundcard)

OutputStream.write() works only with exclusive=False; when using exclusive=True, there is only strange noise.

here is the code used:

from ctypes import windll
import time
import sounddevice as sd
import soundfile as sf

#exclusive = True
audio_dev = 18 #14

data, fs = sf.read('d:\snd_scripts_f\startle50ms.wav', dtype='float32')

wasapi_exclusive = sd.WasapiSettings(exclusive=True)

stream = sd.OutputStream(device = audio_dev,extra_settings=wasapi_exclusive)
stream.start()

#sd.query_devices()

p = windll.inpout32

duration = 0.05
pause = 0.1
repeat = 10000
address = 0xDC00

for i in range(1,repeat+1):
    #sd.play(data,fs,device=audio_dev,extra_settings=wasapi_exclusive)
    stream.write(data)
    p.Out32(address, 255)
    target_time = time.clock() + duration
    while time.clock() < target_time:
        pass
    p.Out32(address, 0)
    time.sleep(pause)

@mgeier
Copy link
Member

mgeier commented Nov 22, 2016

@piotx Thanks for testing this, nice that it (mostly) works!

only 37ms of the 50ms sound are played back

This sounds similar to #44, doesn't it?

I also experienced that in some situations the last few frames are not played with ALSA. This might as well depend on the hardware. With JACK, however, this never happened.

when using exclusive=True, there is only strange noise

Does this only happen with the new PortAudio version?
Either way, this sounds like a PortAudio issue.

@hiccup7 @stefanrepplinger Do you want to try it, too?

I've created a PR for the new dylib/DLL version: #53.

Does anyone have an ASIO device to test?
I guess this could also be tested with ASIO4ALL.

Does anyone of you happen to use 32-bit Windows?
This DLL is yet untested.

@piotx
Copy link
Author

piotx commented Nov 22, 2016

I can do some tests, when I'll be back in one week or so. Exclusive mode
didn't work with the previous PortAudio version, as far as I've
understood... or am I wrong?

btw. I just replaced the portaudio.dll with the new one... I'm using the
32-bit version of portaudio, although I'm on win 64 bit..

@hiccup7
Copy link

hiccup7 commented Nov 22, 2016

Test conditions:

  • libportaudio64bit.dll from the portaudio-19.6.0-win branch
  • USB external DAC
  • Control Panel > Sound > device > Properties > Advanced tab > Exclusive Mode > enable checkboxes
  • 44.1 kHz WAV file data
  • sd.default.dtype = 'int24'
  • sd.RawOutputStream()
  • sounddevice.py from the master branch modified to contain the following code:
        if exclusive:
            flags |= _lib.paWinWasapiExclusive
            flags |= _lib.paWinWasapiThreadPriority
        self._streaminfo = _ffi.new('PaWasapiStreamInfo*', dict(
            size=_ffi.sizeof('PaWasapiStreamInfo'),
            hostApiType=_lib.paWASAPI,
            version=1,
            threadPriority=_lib.eThreadPriorityProAudio,
            flags=flags,
        ))

The following applies when the WASAPI host API device is used:
sd.default.extra_settings = sd.WasapiSettings(exclusive=False) no longer raises an exception, and the Windows volume control has an effect (as expected for shared mode).
sd.default.extra_settings = sd.WasapiSettings(exclusive=True) no longer raises an exception, and the Windows volume control has no effect (as expected for exclusive mode).
Congratulations @mgeier !

With the WDM-KS and ASIO host API devices are used for the same USB external DAC, sd.default.extra_settings = sd.WasapiSettings(exclusive=False) and sd.default.extra_settings = sd.WasapiSettings(exclusive=True) cause sd.RawOutputStream() to raise an exception. Without sd.default.extra_settings, these host APIs play fine.

@mgeier
Copy link
Member

mgeier commented Nov 23, 2016

@hiccup7 Thanks for the thorough test! That's good news!

Did you also try it without modifying sounddevice.py? As far as I understand, it shouldn't be necessary to explicitly change the thread priority.

@hiccup7
Copy link

hiccup7 commented Nov 23, 2016

I tested with the Realtek sound card on my laptop. It works with WASAPI shared mode, but not with exclusive mode. However, JRiver Media Center v22 outputs noise with exclusive mode on the same device. Therefore, I suspect that this sound card is the problem for exclusive mode.

I haven't yet tested any other conditions. I plan to test with the original sounddevice.py file as well as the one from the portaudio-19.6.0-win branch.

Christoph Gohlke added sounddevice to his Windows builds using the same Microsoft compiler as each version of Python uses: http://www.lfd.uci.edu/~gohlke/pythonlibs/#sounddevice
I wonder if he used portaudio v19.6.0. This is another thing to test.

We can expect that a lot more Windows Python users will be using sounddevice now that Christoph has added this support.

@mgeier
Copy link
Member

mgeier commented Nov 23, 2016

FYI, the file sounddevice.py is unchanged in the portaudio-19.6.0-win branch. The only changes are in the submodule with the DLLs.

It's great that the sounddevice module is now part of the Gohlke collection!
I had a look at the textual contents of his DLL, and it seems to use the newest PortAudio release (PortAudio V19.6.0-devel, revision 396fe4b6699ae929d3a685b3ef8a7e97396139a4).

@hiccup7
Copy link

hiccup7 commented Nov 23, 2016

I tested the original sounddevice.py using the same conditions as my post yesterday, and WASAPI exclusive mode works fine.

I documented my testing result just now for cgohlke's wheel at winpython/winpython#428
cgohlke's wheels are most important to the WinPython project because a WinPython bug prevents simple installation of @mgeier wheels in WinPython and inclusion in the next build of WinPython. See winpython/winpython#423

@mgeier
Copy link
Member

mgeier commented Nov 23, 2016

That's great, so there is no need to change sounddevice.py.

I will make a new release soon, but I would like to hear first if the new 32-bit DLL works.
@piotx confirmed that it works when used on 64-bit Windows, but it would be nice if somebody could try it on an actual 32-bit Windows.

@cosacog
Copy link

cosacog commented Nov 28, 2016

I have tested sounddevice with the new 32bit DLL on 32bit Windows 7.
WASAPI exclusive mode works fine and better than shared mode, but WDM-KS was more accurate.

sounddevice new 32bit dll

I recorded the data in 1000 Hz, so 1 ms error is the sampling error.
"With window" means that a window is opened using psychopy. I've experienced before that jitter increases with a window, but there was no difference this time.

Thank you anyway! The performance is good enough.

@mgeier
Copy link
Member

mgeier commented Nov 28, 2016

@cosacog Thanks for testing, it's good to know that the 32bit DLLs work.
Would you also be able to test if ASIO works?

I don't understand those plots, what are they supposed to show?

@cosacog
Copy link

cosacog commented Nov 28, 2016

I played just one time with ASIO, but it failed. It was wired to me that the device number for ASIO was only 14. The other apis like WASAPI and MME had more than one device numbers for input and output.

By the way, each histogram shows the difference between a trigger and a sound with psychopy. With MME, the delay of sound is around 270 ms while the jitter is 5-6 ms. When recording EEG responses after sound, the jitter is a problem because brain responses (evoked potentials) are time locked to the stimulus, and the potentials are blurred by the jitter. Now I am happy to see that the jitter is 1 ms or less with WDM-KS.

@mgeier
Copy link
Member

mgeier commented Nov 28, 2016

I played just one time with ASIO, but it failed.

How did it fail?

... the device number for ASIO was only 14. The other apis like WASAPI and MME had more than one device numbers for input and output.

That's normal, and that's actually an advantage!
With ASIO, you can use all channels at the same time, see also #29.
That's also the reason why I would really like for ASIO to work.

Thanks for explaining the histograms, I think I understand them now. That's really interesting.
How do you create and record the trigger?
How did you play the sounds? Did you use the blocking or the callback method?
Can you provide the code you used? Probably as a Gist?

I would expect that the jitter is highly dependent on the audio block size, right?
Which block sizes/latency settings did you use?
I'd expect the jitter to be in the order of magnitude as the blocksize, so I'm wondering how the jitter can even get as low as 1 ms.

@cosacog
Copy link

cosacog commented Nov 29, 2016

How did it fail?

The error log when playin with asio is as follows:

In [4]: sd.default.device=[14,14]

In [6]: sd.play(mysnd)
------------------------------------------------------------------------
PortAudioError                         Traceback (most recent call last)
<ipython-input-6-c38c2d60cef7> in <module>()
----> 1 sd.play(mysnd)

C:\Users\kyu\Anaconda2\lib\site-packages\sounddevice.pyc in play(data, samplerate, mapping, blocking, loop, **kwargs)
    392                      ctx.output_dtype, callback, blocking,
    393                      prime_output_buffers_using_stream_callback=False,
--> 394                      **kwargs)
    395
    396

C:\Users\kyu\Anaconda2\lib\site-packages\sounddevice.pyc in start_stream(self, StreamClass, samplerate, channels, dtype,
 callback, blocking, **kwargs)
   2467                                   finished_callback=self.finished_callback,
   2468                                   **kwargs)
-> 2469         self.stream.start()
   2470         global _last_callback
   2471         _last_callback = self

C:\Users\kyu\Anaconda2\lib\site-packages\sounddevice.pyc in start(self)
   1119         err = _lib.Pa_StartStream(self._ptr)
   1120         if err != _lib.paStreamIsNotStopped:
-> 1121             _check(err, 'Error starting stream')
   1122
   1123     def stop(self):

C:\Users\kyu\Anaconda2\lib\site-packages\sounddevice.pyc in _check(err, msg)
   2603         else:
   2604             msg += _ffi.string(_lib.Pa_GetErrorText(err)).decode()
-> 2605         raise PortAudioError(msg)
   2606     return err
   2607

PortAudioError: Error starting stream: Unanticipated host API 2 error -1000: u'Hardware input or output is not present or available'

How do you create and record the trigger?

I created trigger through parallel port with psychopy. The script to create trigger and to play sound is here in Gist.

I recorded the trigger out of parallel port and the sound through RCA plug of the PCI-e sound card, using AD converter of EEG measurement system.

I played click (square wave) sound. The plot image of the sound is shown below. The plot means that 441 points out of 88200 points (at 44100 hz) are the sound, so the sound duration is 10 ms.

plt.plot(mysnd)

sound

How did you play the sounds?

Please see the script above. I am sorry but I do not understand the blocking or the callback method enough. I think I used the blocking method.

Which block sizes/latency settings did you use?

I'm sorry again. I don't understand block sizes. The duration of the sound is 10 ms, but maybe it's not the answer.
I tested on default settings, and I don't know how I can check the block sizes for wdm-ks or wasapi.
The buffer size for asio settings is 4 ms.

how the jitter can even get as low as 1 ms.

The delay and jitter is repoted on another thread of psychopy as you know.
The data is better than mine. I also don't know why, but the performance is satisfactory with wdm-ks.
I hope this good performance is retained in future versions.

@mgeier
Copy link
Member

mgeier commented Nov 29, 2016

The ASIO error is unfortunate, but I have no clue what's its cause. Does the same ASIO device work with other PortAudio applications, e.g. Audacity?

Thanks for the Gist, that's very helpful.

So you were using sd.play(), which defines its own callback function. Therefore, you were using the callback API.
To use the "blocking" API, you could use the method OutputStream.write(). This would probably yield different results in your measurements.

I suspect that you jitter measurements may be biased because you repeat the measurements regularly.
I think you should add a pause of random duration between each of the measurements.
If possible, it would also be better to use more than 50 repetitions.

Your while loop looks a bit complicated, couldn't you just use something like this?

p_port.setData(int(1))
sd.play(mysnd, blocking=True)
p_port.setData(int(0))

Whenever you want to wait some time, you can just use time.sleep().

BTW, I just found out that Jon added a sounddevice backend to PsychoPy: https://github.com/psychopy/psychopy/blob/master/psychopy/sound/backend_sounddevice.py
You could probably also try that?

I don't understand block sizes.

The audio drivers and audio frameworks normally don't process the sound sample by sample. They typically work on a bunch of samples at once, which I would call a "block", but there are different names in use.

PortAudio of course also uses blocks internally, and with sounddevice you can e.g. specify the block size with:

sd.default.blocksize = 1024

The blocksize will have an immediate effect on the latency.
The blocksize is typically a power of 2, but you can also choose different numbers.
You should try a few different block sizes and see how your measurements change.

Apart from the blocksize, there is another setting named latency.
TBH, I'm not sure how this is handled in detail in PortAudio, and it may well be platform-dependent.
By default, sounddevice uses the "high latency" settings of PortAudio, to get the low settings, use:

sd.default.latency = 'low'

For some devices, however, the default "high" and "low" settings are actually the same.
You can find this out with sounddevice.query_devices().
You can also specify an arbitrary latency in seconds, e.g.:

sd.default.latency = 0.005

Of course, only a certain range of latencies is physically possible, PortAudio will try to get as close as possible to the value you specified.

Once you have created an OutputStream object, you can get an estimation for the actual latency with http://python-sounddevice.readthedocs.io/en/latest/#sounddevice.Stream.latency.

It would be interesting to know if your measured latencies are similar to those estimated by PortAudio.

@hiccup7
Copy link

hiccup7 commented Nov 29, 2016

I reported ASIO results with the 64-bit DLL a week ago:

With the WDM-KS and ASIO host API devices are used for the same USB external DAC, sd.default.extra_settings = sd.WasapiSettings(exclusive=False) and sd.default.extra_settings = sd.WasapiSettings(exclusive=True) cause sd.RawOutputStream() to raise an exception. Without sd.default.extra_settings, these host APIs play fine.

I would like to set sd.default.extra_settings = sd.WasapiSettings(exclusive=True) as my normal default. It is not intuitive to me that WASAPI settings should cause an exception for WDM-KS and ASIO host API devices. I expect WDM-KS and ASIO host API devices to ignore WASAPI settings.
@mgeier : Would you consider this a bug, an enhancement or not worth the effort to change?

@mgeier
Copy link
Member

mgeier commented Nov 29, 2016

@hiccup7 TBH, I don't know yet. Probably I should change the API completely ...

Can you please open a new issue for that where we can discuss further?

@hiccup7
Copy link

hiccup7 commented Nov 29, 2016

Done. See #55

@cosacog
Copy link

cosacog commented Nov 30, 2016

@mgeier Thank you for a lot of comments and advises. They are very helpful for me to understand the settings.

I will test the measurements according to your advice and the new psychopy sounddevice backend. I am busy for some time, so it will be in a few weeks.

@mgeier
Copy link
Member

mgeier commented Jan 26, 2017

I'm closing this because I think there are no more open questions. Thanks for the discussions!

If there are any more problems/comments/suggestions/..., feel free to create new issues.

@MyGoodBear

This comment has been minimized.

@mgeier

This comment has been minimized.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants