Git Product home page Git Product logo

Comments (68)

mgeier avatar mgeier commented on July 28, 2024

from python-sounddevice.

piotx avatar piotx commented on July 28, 2024

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
.

from python-sounddevice.

mgeier avatar mgeier commented on July 28, 2024

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

from python-sounddevice.

mgeier avatar mgeier commented on July 28, 2024

See also #4.

from python-sounddevice.

mgeier avatar mgeier commented on July 28, 2024

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

from python-sounddevice.

piotx avatar piotx commented on July 28, 2024

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.

from python-sounddevice.

mgeier avatar mgeier commented on July 28, 2024

Sorry, my bad!

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

from python-sounddevice.

piotx avatar piotx commented on July 28, 2024

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

from python-sounddevice.

mgeier avatar mgeier commented on July 28, 2024

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

from python-sounddevice.

piotx avatar piotx commented on July 28, 2024

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

from python-sounddevice.

piotx avatar piotx commented on July 28, 2024

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

from python-sounddevice.

piotx avatar piotx commented on July 28, 2024

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

from python-sounddevice.

piotx avatar piotx commented on July 28, 2024

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..

from python-sounddevice.

mgeier avatar mgeier commented on July 28, 2024

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?

from python-sounddevice.

piotx avatar piotx commented on July 28, 2024

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

from python-sounddevice.

mgeier avatar mgeier commented on July 28, 2024

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.

from python-sounddevice.

piotx avatar piotx commented on July 28, 2024

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

from python-sounddevice.

piotx avatar piotx commented on July 28, 2024

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?

from python-sounddevice.

mgeier avatar mgeier commented on July 28, 2024

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)

from python-sounddevice.

mgeier avatar mgeier commented on July 28, 2024

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.

from python-sounddevice.

piotx avatar piotx commented on July 28, 2024

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...

from python-sounddevice.

mgeier avatar mgeier commented on July 28, 2024

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

from python-sounddevice.

piotx avatar piotx commented on July 28, 2024

Hello Matthias,

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

from python-sounddevice.

stfnrpplngr avatar stfnrpplngr commented on July 28, 2024

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

from python-sounddevice.

mgeier avatar mgeier commented on July 28, 2024

@stefanrepplinger Can you please try with exclusive=False and different numbers for hostApiType? See #35 (comment) for details.

I have no clue what's going wrong here ...

Is WASAPI working at all on your computer?

What is ha_type as mentioned in #35 (comment)?

from python-sounddevice.

stfnrpplngr avatar stfnrpplngr commented on July 28, 2024

Hello,

setting exclusive=False results in the same error.

The default value of wasapi_exclusive._streaminfo.hostApiType is is 13L. Trying different values from 0 to 14 does not change anything.

Running the code without the following lines, a sound is played but not in exclusive mode:

wasapi_exclusive = sd.WasapiSettings(exclusive=True)
sd.default.extra_settings = wasapi_exclusive

Trying what you proposed above to find out the ha_type leads to the following error:

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

Traceback (most recent call last):

  File "<ipython-input-2-59077e7350c2>", line 2, in <module>
    ha_type = sd._lib.Pa_GetStreamHostApiType(mystream._ptr)

  File "C:\Program Files (x86)\PsychoPy2\Lib\site-packages\cffi\api.py", line 850, in __getattr__
    make_accessor(name)

  File "C:\Program Files (x86)\PsychoPy2\Lib\site-packages\cffi\api.py", line 846, in make_accessor
    accessors[name](name)

  File "C:\Program Files (x86)\PsychoPy2\Lib\site-packages\cffi\api.py", line 791, in accessor_function
    raise AttributeError('%s: %s' % (name, e))

AttributeError: Pa_GetStreamHostApiType: "function 'Pa_GetStreamHostApiType' not found in library 'C:\\Anaconda2\\lib\\site-packages\\_sounddevice_data\\libportaudio32bit.dll': error 0x7f"

from python-sounddevice.

mgeier avatar mgeier commented on July 28, 2024

@stefanrepplinger Thanks for checking this out. For the last thing to work, you need a version that has eaede7f included, which should be the case for the latest release. Did you upgrade?

Anyway, I'm not sure if that leads anywhere, I'm just shooting in the dark.

I guess the next thing to try would be to create a little test program in C using the PortAudio API directly to see if it shows the same behavior.

from python-sounddevice.

stfnrpplngr avatar stfnrpplngr commented on July 28, 2024

Hi, I upgraded to the latest version using pip. It makes no difference, same error. Thank you for your help so far. In the moment, I don't have the time to try out your last suggestion, sorry.

from python-sounddevice.

mgeier avatar mgeier commented on July 28, 2024

It makes no difference, same error.

Hmmm, there seem to be some versions of the PortAudio library that don't have Pa_GetStreamHostApiType(). Are you using the bundled DLL? Do you have a file called portaudio.dll somewhere in your Python path?

In the moment, I don't have the time to try out your last suggestion, sorry.

No problem, probably someone else who needs WASAPI exclusive mode will do it. @piotx?

from python-sounddevice.

mgeier avatar mgeier commented on July 28, 2024

@stefanrepplinger See also #36 (comment).

from python-sounddevice.

piotx avatar piotx commented on July 28, 2024

Hey Matthias,

sorry, but right now I'm also too busy with other things...

Best wishes
Piotr

from python-sounddevice.

cosacog avatar cosacog commented on July 28, 2024

Hi, I have the same problem. It appears that the thread below is related to the issue.
http://sites.music.columbia.edu/pipermail/portaudio/2015-March/016614.html

It looks like Audacity is using a patched version of PortAudio.
Pa_GetStreamHostApiType()
was added to their version but not to the official PortAudio source. This
looks like the patch:

I hope it helps.

Katsuya

from python-sounddevice.

mgeier avatar mgeier commented on July 28, 2024

@cosacog Thanks for the hint!

The non-existence of Pa_GetStreamHostApiType() isn't our problem. We actually don't need it. I was just suggesting to use it to try to find out what's going wrong.

There may be a bug in PortAudio, but to find that out, it would be necessary to create a little C program that tries to select WASAPI exclusive mode.

from python-sounddevice.

mgeier avatar mgeier commented on July 28, 2024

@stefanrepplinger and @cosacog Just to make sure, did you actually select a WASAPI device with device='my WASAPI device name' or device=X where X is the device ID of a WASAPI device?

from python-sounddevice.

cosacog avatar cosacog commented on July 28, 2024

@mgeier Thank you for your comment.
I selected WASAPi device by sd.default.device = [ID1, ID2], where ID1 and ID2 is available by sd.query_hostapis() or sd.query_devices().

I hope WASAPi exclusive mode will be available. Until then I try to use wdm-ks or asio.

from python-sounddevice.

hiccup7 avatar hiccup7 commented on July 28, 2024

I installed "sounddevice-0.3.5-py2.py3.cp26.cp27.cp32.cp33.cp34.cp35.cp36.pp27.pp32.pp33.pp34.pp35.pp36-none-win_amd64.whl" in 64-bit WinPython 3.5.2.3Qt5 distribution on Windows 8.1. While WinPython has PyAudio installed, which also uses the PortAudio library, there is no portaudio.dll anywhere in the WinPython folders. Also, the follow code throws an error:

import sounddevice as sd
a = _ffi.dlopen('portaudio')

Therefore, I am confident sounddevice is loading the bundled dll, which does not throw an error.

I used sd.query_devices() for find the device number of the WASAPI version of my USB external DAC device. I used sd.default.device = ID to configure sounddevice to use this device. I am able to use sounddevice to play a WAV file through this device.

The problem I am having is that either of the following commands cause the error "PortAudioError: Error opening OutputStream: Incompatible host API specific stream info"

sd.default.extra_settings = sd.WasapiSettings(exclusive=True)
sd.default.extra_settings = sd.WasapiSettings(exclusive=False)

In fact, changing sd.default.extra_settings with WASAPI settings causes the same error for all host API types.

The problem is the same using the 64-bit release DLL from https://github.com/adfernandes/precompiled-portaudio-windows

I have JRiver Media Center v22, and my USB external DAC sounds great with WASAPI exclusive mode, but distorted with WASAPI shared mode and other host APIs. Therefore I sounddevice isn't useful for me unless it supports WASAPI exclusive mode.

from python-sounddevice.

hiccup7 avatar hiccup7 commented on July 28, 2024

Maybe we need a separate DLL where WASAPI is forced to exclusive mode. I would be satisfied to use different DLLs for WASAPI exclusive mode and WASAPI shared mode. Does this link provide the needed info on how to modify the PortAudio code and configure the build (--enable-shared=no)?
http://stackoverflow.com/questions/31306010/how-to-enable-wasapi-exclusive-mode-in-pyaudio

from python-sounddevice.

mgeier avatar mgeier commented on July 28, 2024

Probably it works only if the thread priority is changed to eThreadPriorityProAudio? I thought that was the default behavior anyway, but probably I misunderstood the documentation.

There is no need for a separate DLL to try this, it can be directly done in Python code.

The flags are set here:

flags |= _lib.paWinWasapiExclusive

You'll see that it looks already quite similar to the code in the stackoverflow answer.

There you could add another line like this:

flags |= _lib.paWinWasapiThreadPriority

And a few lines below, you could add:

threadPriority=_lib.eThreadPriorityProAudio,

Does that work?

from python-sounddevice.

hiccup7 avatar hiccup7 commented on July 28, 2024

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..

@piotx : I reproduced and diagnosed this problem, and I created a new issue #52 for it.

from python-sounddevice.

hiccup7 avatar hiccup7 commented on July 28, 2024

@mgeier - I modified sounddevice.py to add the two lines as you suggested. Did I do it correctly?

        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,
        ))

I still get the same problem as before the edit, which is that either of the following commands cause the error "PortAudioError: Error opening OutputStream: Incompatible host API specific stream info"

sd.default.extra_settings = sd.WasapiSettings(exclusive=True)
sd.default.extra_settings = sd.WasapiSettings(exclusive=False)

from python-sounddevice.

hiccup7 avatar hiccup7 commented on July 28, 2024

A reminder to Windows users: for WASAPI exclusive mode to work, you must do the following:
Control Panel > Sound > device > Properties > Advanced tab > Exclusive Mode
Enable checkboxes:
"Allow applications to take exclusive control of this device"
"Give exclusive mode applications priority"

from python-sounddevice.

mgeier avatar mgeier commented on July 28, 2024

@hiccup7 Thanks for checking this out!

The code is now equivalent to what is shown in the stackoverflow answer you brought up: http://stackoverflow.com/questions/31306010/how-to-enable-wasapi-exclusive-mode-in-pyaudio

The compiler option --enable-shared=no doesn't have anything to do with WASAPI "shared" mode, it is about "shared" libraries.

I'm out of ideas, what else could we try?

from python-sounddevice.

hiccup7 avatar hiccup7 commented on July 28, 2024

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.

from python-sounddevice.

mgeier avatar mgeier commented on July 28, 2024

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!

from python-sounddevice.

hiccup7 avatar hiccup7 commented on July 28, 2024

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?

from python-sounddevice.

mgeier avatar mgeier commented on July 28, 2024

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

from python-sounddevice.

cosacog avatar cosacog commented on July 28, 2024

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.

from python-sounddevice.

piotx avatar piotx commented on July 28, 2024

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...

from python-sounddevice.

piotx avatar piotx commented on July 28, 2024

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)

from python-sounddevice.

mgeier avatar mgeier commented on July 28, 2024

@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.

from python-sounddevice.

piotx avatar piotx commented on July 28, 2024

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..

from python-sounddevice.

hiccup7 avatar hiccup7 commented on July 28, 2024

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.

from python-sounddevice.

mgeier avatar mgeier commented on July 28, 2024

@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.

from python-sounddevice.

hiccup7 avatar hiccup7 commented on July 28, 2024

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.

from python-sounddevice.

mgeier avatar mgeier commented on July 28, 2024

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).

from python-sounddevice.

hiccup7 avatar hiccup7 commented on July 28, 2024

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

from python-sounddevice.

mgeier avatar mgeier commented on July 28, 2024

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.

from python-sounddevice.

cosacog avatar cosacog commented on July 28, 2024

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.

from python-sounddevice.

mgeier avatar mgeier commented on July 28, 2024

@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?

from python-sounddevice.

cosacog avatar cosacog commented on July 28, 2024

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.

from python-sounddevice.

mgeier avatar mgeier commented on July 28, 2024

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.

from python-sounddevice.

cosacog avatar cosacog commented on July 28, 2024

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.

from python-sounddevice.

mgeier avatar mgeier commented on July 28, 2024

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.

from python-sounddevice.

hiccup7 avatar hiccup7 commented on July 28, 2024

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?

from python-sounddevice.

mgeier avatar mgeier commented on July 28, 2024

@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?

from python-sounddevice.

hiccup7 avatar hiccup7 commented on July 28, 2024

Done. See #55

from python-sounddevice.

cosacog avatar cosacog commented on July 28, 2024

@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.

from python-sounddevice.

mgeier avatar mgeier commented on July 28, 2024

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.

from python-sounddevice.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.