Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-sounddevice for 
openSUSE:Factory checked in at 2022-10-08 01:26:10
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-sounddevice (Old)
 and      /work/SRC/openSUSE:Factory/.python-sounddevice.new.2275 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-sounddevice"

Sat Oct  8 01:26:10 2022 rev:11 rq:1008875 version:0.4.5

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-sounddevice/python-sounddevice.changes    
2021-04-19 21:06:08.768042576 +0200
+++ 
/work/SRC/openSUSE:Factory/.python-sounddevice.new.2275/python-sounddevice.changes
  2022-10-08 01:26:34.274414915 +0200
@@ -1,0 +2,8 @@
+Fri Oct  7 16:18:39 UTC 2022 - Yogalakshmi Arunachalam <yarunacha...@suse.com>
+
+- Update to version 0.4.5 
+  * Add index field to device dict
+  * Require Python >= 3.7
+  * Add PaWasapi_IsLoopback() to cdef (high-level interface not yet available)
+
+-------------------------------------------------------------------

Old:
----
  sounddevice-0.4.1.tar.gz

New:
----
  sounddevice-0.4.5.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-sounddevice.spec ++++++
--- /var/tmp/diff_new_pack.UvS91K/_old  2022-10-08 01:26:34.650415778 +0200
+++ /var/tmp/diff_new_pack.UvS91K/_new  2022-10-08 01:26:34.654415787 +0200
@@ -1,7 +1,7 @@
 #
 # spec file for package python-sounddevice
 #
-# Copyright (c) 2021 SUSE LLC
+# Copyright (c) 2022 SUSE LLC
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -20,7 +20,7 @@
 %define skip_python2 1
 %define skip_python36 1
 Name:           python-sounddevice
-Version:        0.4.1
+Version:        0.4.5
 Release:        0
 Summary:        Module to play and record sound with Python
 License:        MIT

++++++ sounddevice-0.4.1.tar.gz -> sounddevice-0.4.5.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sounddevice-0.4.1/CONTRIBUTING.rst 
new/sounddevice-0.4.5/CONTRIBUTING.rst
--- old/sounddevice-0.4.1/CONTRIBUTING.rst      2020-09-23 12:45:04.000000000 
+0200
+++ new/sounddevice-0.4.5/CONTRIBUTING.rst      2021-10-12 22:18:35.000000000 
+0200
@@ -126,4 +126,4 @@
 
 The generated files will be available in the directory ``build/sphinx/html/``.
 
-.. _Sphinx: http://sphinx-doc.org/
+.. _Sphinx: https://www.sphinx-doc.org/
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sounddevice-0.4.1/LICENSE 
new/sounddevice-0.4.5/LICENSE
--- old/sounddevice-0.4.1/LICENSE       2020-07-15 17:23:35.000000000 +0200
+++ new/sounddevice-0.4.5/LICENSE       2022-08-21 17:22:18.000000000 +0200
@@ -1,4 +1,4 @@
-Copyright (c) 2015-2020 Matthias Geier
+Copyright (c) 2015-2022 Matthias Geier
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sounddevice-0.4.1/NEWS.rst 
new/sounddevice-0.4.5/NEWS.rst
--- old/sounddevice-0.4.1/NEWS.rst      2020-09-26 19:14:45.000000000 +0200
+++ new/sounddevice-0.4.5/NEWS.rst      2022-08-21 17:24:03.000000000 +0200
@@ -1,3 +1,19 @@
+0.4.5 (2022-08-21):
+ * Add ``index`` field to device dict
+ * Require Python >= 3.7
+ * Add PaWasapi_IsLoopback() to cdef (high-level interface not yet available)
+
+0.4.4 (2021-12-31):
+ * Exact device string matches can now include the host API name
+
+0.4.3 (2021-10-20):
+ * Fix dimension check in `Stream.write()`
+ * Provide "universal" (x86_64 and arm64) ``.dylib`` for macOS
+
+0.4.2 (2021-07-18):
+ * Update PortAudio binaries to version 19.7.0
+ * Wheel names are now shorter
+
 0.4.1 (2020-09-26):
  * `CallbackFlags` attributes are now writable
 
@@ -73,13 +89,13 @@
 
 0.2.0 (2015-07-03):
  * Support for wheels including a dylib for Mac OS X and DLLs for Windows.
-   The code for creating the wheels is largely taken from PySoundFile_.
+   The code for creating the wheels is largely taken from the soundfile_ 
module.
  * Remove logging (this seemed too intrusive)
  * Return callback status from `wait()` and add the new function `get_status()`
  * `playrec()`: Rename the arguments *input_channels* and *input_dtype*
    to *channels* and *dtype*, respectively
 
-   .. _PySoundFile: https://github.com/bastibe/SoundFile/
+   .. _soundfile: https://github.com/bastibe/python-soundfile/
 
 0.1.0 (2015-06-20):
    Initial release.  Some ideas are taken from PySoundCard_.  Thanks to Bastian
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sounddevice-0.4.1/PKG-INFO 
new/sounddevice-0.4.5/PKG-INFO
--- old/sounddevice-0.4.1/PKG-INFO      2020-09-26 19:17:25.373517000 +0200
+++ new/sounddevice-0.4.5/PKG-INFO      2022-08-21 17:36:27.595208600 +0200
@@ -1,32 +1,12 @@
 Metadata-Version: 2.1
 Name: sounddevice
-Version: 0.4.1
+Version: 0.4.5
 Summary: Play and Record Sound with Python
 Home-page: http://python-sounddevice.readthedocs.io/
 Author: Matthias Geier
 Author-email: matthias.ge...@gmail.com
 License: MIT
-Description: Play and Record Sound with Python
-        =================================
-        
-        This Python_ module provides bindings for the PortAudio_ library and a 
few
-        convenience functions to play and record NumPy_ arrays containing 
audio signals.
-        
-        The ``sounddevice`` module is available for Linux, macOS and Windows.
-        
-        Documentation:
-           https://python-sounddevice.readthedocs.io/
-        
-        Source code repository and issue tracker:
-           https://github.com/spatialaudio/python-sounddevice/
-        
-        License:
-           MIT -- see the file ``LICENSE`` for details.
-        
-        .. _Python: https://www.python.org/
-        .. _PortAudio: http://www.portaudio.com/
-        .. _NumPy: https://numpy.org/
-        
+Project-URL: Source, https://github.com/spatialaudio/python-sounddevice
 Keywords: sound,audio,PortAudio,play,record,playrec
 Platform: any
 Classifier: License :: OSI Approved :: MIT License
@@ -34,5 +14,27 @@
 Classifier: Programming Language :: Python
 Classifier: Programming Language :: Python :: 3
 Classifier: Topic :: Multimedia :: Sound/Audio
-Requires-Python: >=3
+Requires-Python: >=3.7
 Provides-Extra: NumPy
+License-File: LICENSE
+
+Play and Record Sound with Python
+=================================
+
+This Python_ module provides bindings for the PortAudio_ library and a few
+convenience functions to play and record NumPy_ arrays containing audio 
signals.
+
+The ``sounddevice`` module is available for Linux, macOS and Windows.
+
+Documentation:
+   https://python-sounddevice.readthedocs.io/
+
+Source code repository and issue tracker:
+   https://github.com/spatialaudio/python-sounddevice/
+
+License:
+   MIT -- see the file ``LICENSE`` for details.
+
+.. _Python: https://www.python.org/
+.. _PortAudio: http://www.portaudio.com/
+.. _NumPy: https://numpy.org/
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sounddevice-0.4.1/doc/CONTRIBUTING.rst 
new/sounddevice-0.4.5/doc/CONTRIBUTING.rst
--- old/sounddevice-0.4.1/doc/CONTRIBUTING.rst  2020-09-23 12:45:04.000000000 
+0200
+++ new/sounddevice-0.4.5/doc/CONTRIBUTING.rst  2021-10-12 22:18:35.000000000 
+0200
@@ -126,4 +126,4 @@
 
 The generated files will be available in the directory ``build/sphinx/html/``.
 
-.. _Sphinx: http://sphinx-doc.org/
+.. _Sphinx: https://www.sphinx-doc.org/
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sounddevice-0.4.1/doc/api/checking-hardware.rst 
new/sounddevice-0.4.5/doc/api/checking-hardware.rst
--- old/sounddevice-0.4.1/doc/api/checking-hardware.rst 2020-07-15 
17:23:35.000000000 +0200
+++ new/sounddevice-0.4.5/doc/api/checking-hardware.rst 2022-07-19 
19:26:16.000000000 +0200
@@ -3,14 +3,16 @@
 
 .. currentmodule:: sounddevice
 
-.. autosummary::
-   :nosignatures:
+.. topic:: Overview
 
-   query_devices
-   DeviceList
-   query_hostapis
-   check_input_settings
-   check_output_settings
+   .. autosummary::
+      :nosignatures:
+   
+      query_devices
+      DeviceList
+      query_hostapis
+      check_input_settings
+      check_output_settings
 
 .. autofunction:: query_devices
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sounddevice-0.4.1/doc/api/convenience-functions.rst 
new/sounddevice-0.4.5/doc/api/convenience-functions.rst
--- old/sounddevice-0.4.1/doc/api/convenience-functions.rst     2020-07-15 
17:23:35.000000000 +0200
+++ new/sounddevice-0.4.5/doc/api/convenience-functions.rst     2022-07-19 
19:26:16.000000000 +0200
@@ -3,16 +3,18 @@
 
 .. currentmodule:: sounddevice
 
-.. autosummary::
-   :nosignatures:
+.. topic:: Overview
 
-   play
-   rec
-   playrec
-   wait
-   stop
-   get_status
-   get_stream
+   .. autosummary::
+      :nosignatures:
+   
+      play
+      rec
+      playrec
+      wait
+      stop
+      get_status
+      get_stream
 
 .. autofunction:: play
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sounddevice-0.4.1/doc/api/expert-mode.rst 
new/sounddevice-0.4.5/doc/api/expert-mode.rst
--- old/sounddevice-0.4.1/doc/api/expert-mode.rst       2020-07-15 
17:23:35.000000000 +0200
+++ new/sounddevice-0.4.5/doc/api/expert-mode.rst       2022-07-19 
19:26:16.000000000 +0200
@@ -3,13 +3,15 @@
 
 .. currentmodule:: sounddevice
 
-.. autosummary::
-   :nosignatures:
+.. topic:: Overview
 
-   _initialize
-   _terminate
-   _split
-   _StreamBase
+   .. autosummary::
+      :nosignatures:
+   
+      _initialize
+      _terminate
+      _split
+      _StreamBase
 
 .. autofunction:: _initialize
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sounddevice-0.4.1/doc/api/misc.rst 
new/sounddevice-0.4.5/doc/api/misc.rst
--- old/sounddevice-0.4.1/doc/api/misc.rst      2020-07-25 21:44:37.000000000 
+0200
+++ new/sounddevice-0.4.5/doc/api/misc.rst      2022-07-19 19:26:16.000000000 
+0200
@@ -3,15 +3,17 @@
 
 .. currentmodule:: sounddevice
 
-.. autosummary::
-   :nosignatures:
+.. topic:: Overview
 
-   sleep
-   get_portaudio_version
-   CallbackFlags
-   CallbackStop
-   CallbackAbort
-   PortAudioError
+   .. autosummary::
+      :nosignatures:
+   
+      sleep
+      get_portaudio_version
+      CallbackFlags
+      CallbackStop
+      CallbackAbort
+      PortAudioError
 
 .. autofunction:: sleep
 
@@ -20,8 +22,8 @@
 .. autoclass:: CallbackFlags
    :members:
 
-.. autoclass:: CallbackStop
+.. autoexception:: CallbackStop
 
-.. autoclass:: CallbackAbort
+.. autoexception:: CallbackAbort
 
-.. autoclass:: PortAudioError
+.. autoexception:: PortAudioError
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sounddevice-0.4.1/doc/api/module-defaults.rst 
new/sounddevice-0.4.5/doc/api/module-defaults.rst
--- old/sounddevice-0.4.1/doc/api/module-defaults.rst   2020-07-15 
17:23:35.000000000 +0200
+++ new/sounddevice-0.4.5/doc/api/module-defaults.rst   2022-07-19 
19:26:16.000000000 +0200
@@ -3,10 +3,5 @@
 
 .. currentmodule:: sounddevice
 
-.. autosummary::
-   :nosignatures:
-
-   default
-
 .. autoclass:: default
    :members:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/sounddevice-0.4.1/doc/api/platform-specific-settings.rst 
new/sounddevice-0.4.5/doc/api/platform-specific-settings.rst
--- old/sounddevice-0.4.1/doc/api/platform-specific-settings.rst        
2020-07-15 17:23:35.000000000 +0200
+++ new/sounddevice-0.4.5/doc/api/platform-specific-settings.rst        
2022-07-19 19:26:16.000000000 +0200
@@ -3,12 +3,14 @@
 
 .. currentmodule:: sounddevice
 
-.. autosummary::
-   :nosignatures:
+.. topic:: Overview
 
-   AsioSettings
-   CoreAudioSettings
-   WasapiSettings
+   .. autosummary::
+      :nosignatures:
+   
+      AsioSettings
+      CoreAudioSettings
+      WasapiSettings
 
 .. autoclass:: AsioSettings
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sounddevice-0.4.1/doc/api/raw-streams.rst 
new/sounddevice-0.4.5/doc/api/raw-streams.rst
--- old/sounddevice-0.4.1/doc/api/raw-streams.rst       2020-07-15 
17:23:35.000000000 +0200
+++ new/sounddevice-0.4.5/doc/api/raw-streams.rst       2022-07-19 
19:26:16.000000000 +0200
@@ -3,12 +3,14 @@
 
 .. currentmodule:: sounddevice
 
-.. autosummary::
-   :nosignatures:
+.. topic:: Overview
 
-   RawStream
-   RawInputStream
-   RawOutputStream
+   .. autosummary::
+      :nosignatures:
+   
+      RawStream
+      RawInputStream
+      RawOutputStream
 
 .. autoclass:: RawStream
    :members: read, write
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sounddevice-0.4.1/doc/api/streams.rst 
new/sounddevice-0.4.5/doc/api/streams.rst
--- old/sounddevice-0.4.1/doc/api/streams.rst   2020-07-15 17:23:35.000000000 
+0200
+++ new/sounddevice-0.4.5/doc/api/streams.rst   2022-07-19 19:26:16.000000000 
+0200
@@ -3,12 +3,14 @@
 
 .. currentmodule:: sounddevice
 
-.. autosummary::
-   :nosignatures:
+.. topic:: Overview
 
-   Stream
-   InputStream
-   OutputStream
+   .. autosummary::
+      :nosignatures:
+   
+      Stream
+      InputStream
+      OutputStream
 
 .. autoclass:: Stream
    :members:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sounddevice-0.4.1/doc/conf.py 
new/sounddevice-0.4.5/doc/conf.py
--- old/sounddevice-0.4.1/doc/conf.py   2020-08-04 20:57:56.000000000 +0200
+++ new/sounddevice-0.4.5/doc/conf.py   2021-07-18 12:17:30.000000000 +0200
@@ -16,6 +16,7 @@
     'sphinx.ext.intersphinx',
     'sphinx.ext.viewcode',
     'sphinx.ext.napoleon',  # support for NumPy-style docstrings
+    'sphinx_last_updated_by_git',
 ]
 
 autoclass_content = 'init'
@@ -41,7 +42,6 @@
 
 authors = 'Matthias Geier'
 project = 'python-sounddevice'
-copyright = '2020, ' + authors
 
 try:
     release = check_output(['git', 'describe', '--tags', '--always'])
@@ -59,14 +59,15 @@
 
 nitpicky = True
 
-html_theme = 'sphinx_rtd_theme'
+html_theme = 'insipid'
 html_theme_options = {
-    'collapse_navigation': False,
 }
 html_title = project + ', version ' + release
+html_favicon = 'favicon.svg'
 html_domain_indices = False
-html_show_sourcelink = True
 html_show_copyright = False
+html_copy_source = False
+html_permalinks_icon = '??'
 htmlhelp_basename = 'python-sounddevice'
 
 latex_elements = {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sounddevice-0.4.1/doc/examples.rst 
new/sounddevice-0.4.5/doc/examples.rst
--- old/sounddevice-0.4.1/doc/examples.rst      2020-08-04 20:57:56.000000000 
+0200
+++ new/sounddevice-0.4.5/doc/examples.rst      2021-07-18 12:15:42.000000000 
+0200
@@ -14,6 +14,13 @@
 
 .. literalinclude:: ../examples/play_long_file.py
 
+Play a Very Long Sound File without Using NumPy
+-----------------------------------------------
+
+:gh-example:`play_long_file_raw.py`
+
+.. literalinclude:: ../examples/play_long_file_raw.py
+
 Play a Web Stream
 -----------------
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sounddevice-0.4.1/doc/fake__sounddevice.py 
new/sounddevice-0.4.5/doc/fake__sounddevice.py
--- old/sounddevice-0.4.1/doc/fake__sounddevice.py      2020-07-15 
17:23:35.000000000 +0200
+++ new/sounddevice-0.4.5/doc/fake__sounddevice.py      2022-04-11 
23:18:43.000000000 +0200
@@ -17,7 +17,7 @@
 ctypes.util.find_library = new_find_library
 
 
-class ffi(object):
+class ffi:
 
     NULL = NotImplemented
     I_AM_FAKE = True  # This is used for the documentation of "default"
@@ -29,7 +29,7 @@
 ffi = ffi()
 
 
-class FakeLibrary(object):
+class FakeLibrary:
 
     # from portaudio.h:
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sounddevice-0.4.1/doc/installation.rst 
new/sounddevice-0.4.5/doc/installation.rst
--- old/sounddevice-0.4.1/doc/installation.rst  2020-09-23 12:45:04.000000000 
+0200
+++ new/sounddevice-0.4.5/doc/installation.rst  2022-07-19 18:50:21.000000000 
+0200
@@ -12,7 +12,7 @@
    .. image:: 
https://anaconda.org/conda-forge/python-sounddevice/badges/version.svg
       :target: https://anaconda.org/conda-forge/python-sounddevice
 
-If you are using the ``conda`` package manager (e.g. with Anaconda_ for
+If you are using the ``conda`` package manager (e.g. with Anaconda_ or 
Miniconda_ for
 Linux/macOS/Windows), you can install the ``sounddevice`` module from the
 ``conda-forge`` channel::
 
@@ -45,11 +45,6 @@
 If you want to try the latest development version, have a look at the section
 about :doc:`CONTRIBUTING`.
 
-.. only:: html
-
-   .. image:: https://badge.fury.io/py/sounddevice.svg
-      :target: https://pypi.org/project/sounddevice/
-
 To install the latest release from PyPI, use::
 
    python3 -m pip install sounddevice
@@ -86,6 +81,7 @@
 .. _NumPy: https://numpy.org/
 .. _Python: https://www.python.org/
 .. _Anaconda: https://www.anaconda.com/products/individual#Downloads
+.. _Miniconda: https://docs.conda.io/miniconda.html
 .. _WinPython: https://winpython.github.io/
 .. _CFFI: https://cffi.readthedocs.io/
 .. _PyPI: https://pypi.org/project/sounddevice/
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sounddevice-0.4.1/doc/requirements.txt 
new/sounddevice-0.4.5/doc/requirements.txt
--- old/sounddevice-0.4.1/doc/requirements.txt  2020-07-15 17:23:35.000000000 
+0200
+++ new/sounddevice-0.4.5/doc/requirements.txt  2022-08-21 17:06:06.000000000 
+0200
@@ -1,4 +1,2 @@
-Jinja2
-Pygments
-Sphinx
-Sphinx-RTD-Theme
+insipid-sphinx-theme
+sphinx-last-updated-by-git
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sounddevice-0.4.1/examples/play_file.py 
new/sounddevice-0.4.5/examples/play_file.py
--- old/sounddevice-0.4.1/examples/play_file.py 2020-07-15 17:23:35.000000000 
+0200
+++ new/sounddevice-0.4.5/examples/play_file.py 2022-03-21 22:19:39.000000000 
+0100
@@ -1,15 +1,28 @@
 #!/usr/bin/env python3
 """Load an audio file into memory and play its contents.
 
-NumPy and the soundfile module (https://PySoundFile.readthedocs.io/)
+NumPy and the soundfile module (https://python-soundfile.readthedocs.io/)
 must be installed for this to work.
 
 This example program loads the whole file into memory before starting
 playback.
 To play very long files, you should use play_long_file.py instead.
 
+This example could simply be implemented like this::
+
+    import sounddevice as sd
+    import soundfile as sf
+
+    data, fs = sf.read('my-file.wav')
+    sd.play(data, fs)
+    sd.wait()
+
+... but in this example we show a more low-level implementation
+using a callback stream.
+
 """
 import argparse
+import threading
 
 import sounddevice as sd
 import soundfile as sf
@@ -43,13 +56,30 @@
     help='output device (numeric ID or substring)')
 args = parser.parse_args(remaining)
 
+event = threading.Event()
+
 try:
-    data, fs = sf.read(args.filename, dtype='float32')
-    sd.play(data, fs, device=args.device)
-    status = sd.wait()
+    data, fs = sf.read(args.filename, always_2d=True)
+
+    current_frame = 0
+
+    def callback(outdata, frames, time, status):
+        global current_frame
+        if status:
+            print(status)
+        chunksize = min(len(data) - current_frame, frames)
+        outdata[:chunksize] = data[current_frame:current_frame + chunksize]
+        if chunksize < frames:
+            outdata[chunksize:] = 0
+            raise sd.CallbackStop()
+        current_frame += chunksize
+
+    stream = sd.OutputStream(
+        samplerate=fs, device=args.device, channels=data.shape[1],
+        callback=callback, finished_callback=event.set)
+    with stream:
+        event.wait()  # Wait until playback is finished
 except KeyboardInterrupt:
     parser.exit('\nInterrupted by user')
 except Exception as e:
     parser.exit(type(e).__name__ + ': ' + str(e))
-if status:
-    parser.exit('Error during playback: ' + str(status))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sounddevice-0.4.1/examples/play_long_file.py 
new/sounddevice-0.4.5/examples/play_long_file.py
--- old/sounddevice-0.4.1/examples/play_long_file.py    2020-08-04 
20:57:56.000000000 +0200
+++ new/sounddevice-0.4.5/examples/play_long_file.py    2021-07-18 
12:15:42.000000000 +0200
@@ -1,16 +1,16 @@
 #!/usr/bin/env python3
 """Play an audio file using a limited amount of memory.
 
-The soundfile module (https://PySoundFile.readthedocs.io/) must be
-installed for this to work.  NumPy is not needed.
+The soundfile module (https://python-soundfile.readthedocs.io/) must be
+installed for this to work.
 
 In contrast to play_file.py, which loads the whole file into memory
 before starting playback, this example program only holds a given number
 of audio blocks in memory and is therefore able to play files that are
 larger than the available RAM.
 
-A similar example could of course be implemented using NumPy,
-but this example shows what can be done when NumPy is not available.
+This example is implemented using NumPy, see play_long_file_raw.py
+for a version that doesn't need NumPy.
 
 """
 import argparse
@@ -77,7 +77,7 @@
         raise sd.CallbackAbort from e
     if len(data) < len(outdata):
         outdata[:len(data)] = data
-        outdata[len(data):] = b'\x00' * (len(outdata) - len(data))
+        outdata[len(data):].fill(0)
         raise sd.CallbackStop
     else:
         outdata[:] = data
@@ -86,18 +86,18 @@
 try:
     with sf.SoundFile(args.filename) as f:
         for _ in range(args.buffersize):
-            data = f.buffer_read(args.blocksize, dtype='float32')
-            if not data:
+            data = f.read(args.blocksize)
+            if not len(data):
                 break
             q.put_nowait(data)  # Pre-fill queue
-        stream = sd.RawOutputStream(
+        stream = sd.OutputStream(
             samplerate=f.samplerate, blocksize=args.blocksize,
-            device=args.device, channels=f.channels, dtype='float32',
+            device=args.device, channels=f.channels,
             callback=callback, finished_callback=event.set)
         with stream:
             timeout = args.blocksize * args.buffersize / f.samplerate
-            while data:
-                data = f.buffer_read(args.blocksize, dtype='float32')
+            while len(data):
+                data = f.read(args.blocksize)
                 q.put(data, timeout=timeout)
             event.wait()  # Wait until playback is finished
 except KeyboardInterrupt:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sounddevice-0.4.1/examples/play_long_file_raw.py 
new/sounddevice-0.4.5/examples/play_long_file_raw.py
--- old/sounddevice-0.4.1/examples/play_long_file_raw.py        1970-01-01 
01:00:00.000000000 +0100
+++ new/sounddevice-0.4.5/examples/play_long_file_raw.py        2021-07-18 
12:15:42.000000000 +0200
@@ -0,0 +1,100 @@
+#!/usr/bin/env python3
+"""Play an audio file using a limited amount of memory.
+
+This is the same as play_long_file.py, but implemented without using NumPy.
+
+"""
+import argparse
+import queue
+import sys
+import threading
+
+import sounddevice as sd
+import soundfile as sf
+
+
+def int_or_str(text):
+    """Helper function for argument parsing."""
+    try:
+        return int(text)
+    except ValueError:
+        return text
+
+
+parser = argparse.ArgumentParser(add_help=False)
+parser.add_argument(
+    '-l', '--list-devices', action='store_true',
+    help='show list of audio devices and exit')
+args, remaining = parser.parse_known_args()
+if args.list_devices:
+    print(sd.query_devices())
+    parser.exit(0)
+parser = argparse.ArgumentParser(
+    description=__doc__,
+    formatter_class=argparse.RawDescriptionHelpFormatter,
+    parents=[parser])
+parser.add_argument(
+    'filename', metavar='FILENAME',
+    help='audio file to be played back')
+parser.add_argument(
+    '-d', '--device', type=int_or_str,
+    help='output device (numeric ID or substring)')
+parser.add_argument(
+    '-b', '--blocksize', type=int, default=2048,
+    help='block size (default: %(default)s)')
+parser.add_argument(
+    '-q', '--buffersize', type=int, default=20,
+    help='number of blocks used for buffering (default: %(default)s)')
+args = parser.parse_args(remaining)
+if args.blocksize == 0:
+    parser.error('blocksize must not be zero')
+if args.buffersize < 1:
+    parser.error('buffersize must be at least 1')
+
+q = queue.Queue(maxsize=args.buffersize)
+event = threading.Event()
+
+
+def callback(outdata, frames, time, status):
+    assert frames == args.blocksize
+    if status.output_underflow:
+        print('Output underflow: increase blocksize?', file=sys.stderr)
+        raise sd.CallbackAbort
+    assert not status
+    try:
+        data = q.get_nowait()
+    except queue.Empty as e:
+        print('Buffer is empty: increase buffersize?', file=sys.stderr)
+        raise sd.CallbackAbort from e
+    if len(data) < len(outdata):
+        outdata[:len(data)] = data
+        outdata[len(data):] = b'\x00' * (len(outdata) - len(data))
+        raise sd.CallbackStop
+    else:
+        outdata[:] = data
+
+
+try:
+    with sf.SoundFile(args.filename) as f:
+        for _ in range(args.buffersize):
+            data = f.buffer_read(args.blocksize, dtype='float32')
+            if not data:
+                break
+            q.put_nowait(data)  # Pre-fill queue
+        stream = sd.RawOutputStream(
+            samplerate=f.samplerate, blocksize=args.blocksize,
+            device=args.device, channels=f.channels, dtype='float32',
+            callback=callback, finished_callback=event.set)
+        with stream:
+            timeout = args.blocksize * args.buffersize / f.samplerate
+            while data:
+                data = f.buffer_read(args.blocksize, dtype='float32')
+                q.put(data, timeout=timeout)
+            event.wait()  # Wait until playback is finished
+except KeyboardInterrupt:
+    parser.exit('\nInterrupted by user')
+except queue.Full:
+    # A timeout occurred, i.e. there was an error in the callback
+    parser.exit(1)
+except Exception as e:
+    parser.exit(type(e).__name__ + ': ' + str(e))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sounddevice-0.4.1/examples/plot_input.py 
new/sounddevice-0.4.5/examples/plot_input.py
--- old/sounddevice-0.4.1/examples/plot_input.py        2020-07-15 
17:23:35.000000000 +0200
+++ new/sounddevice-0.4.5/examples/plot_input.py        2022-04-11 
23:18:43.000000000 +0200
@@ -100,7 +100,7 @@
     fig, ax = plt.subplots()
     lines = ax.plot(plotdata)
     if len(args.channels) > 1:
-        ax.legend(['channel {}'.format(c) for c in args.channels],
+        ax.legend([f'channel {c}' for c in args.channels],
                   loc='lower left', ncol=len(args.channels))
     ax.axis((0, len(plotdata), -1, 1))
     ax.set_yticks([0])
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sounddevice-0.4.1/examples/rec_gui.py 
new/sounddevice-0.4.5/examples/rec_gui.py
--- old/sounddevice-0.4.1/examples/rec_gui.py   2020-07-15 17:23:35.000000000 
+0200
+++ new/sounddevice-0.4.5/examples/rec_gui.py   2022-06-03 20:11:50.000000000 
+0200
@@ -42,39 +42,36 @@
 
     def body(self, master):
         ttk.Label(master, text='Select host API:').pack(anchor='w')
-        hostapi_list = ttk.Combobox(master, state='readonly', width=50)
-        hostapi_list.pack()
-        hostapi_list['values'] = [hostapi['name']
-                                  for hostapi in sd.query_hostapis()]
+        self.hostapi_list = ttk.Combobox(master, state='readonly', width=50)
+        self.hostapi_list.pack()
+        self.hostapi_list['values'] = [
+            hostapi['name'] for hostapi in sd.query_hostapis()]
 
         ttk.Label(master, text='Select sound device:').pack(anchor='w')
-        device_ids = []
-        device_list = ttk.Combobox(master, state='readonly', width=50)
-        device_list.pack()
-
-        def update_device_list(*args):
-            hostapi = sd.query_hostapis(hostapi_list.current())
-            nonlocal device_ids
-            device_ids = [
-                idx
-                for idx in hostapi['devices']
-                if sd.query_devices(idx)['max_output_channels'] > 0]
-            device_list['values'] = [
-                sd.query_devices(idx)['name'] for idx in device_ids]
-            default = hostapi['default_output_device']
-            if default >= 0:
-                device_list.current(device_ids.index(default))
-                device_list.event_generate('<<ComboboxSelected>>')
-
-        def select_device(*args):
-            self.result = device_ids[device_list.current()]
-
-        hostapi_list.bind('<<ComboboxSelected>>', update_device_list)
-        device_list.bind('<<ComboboxSelected>>', select_device)
+        self.device_ids = []
+        self.device_list = ttk.Combobox(master, state='readonly', width=50)
+        self.device_list.pack()
 
+        self.hostapi_list.bind('<<ComboboxSelected>>', self.update_device_list)
         with contextlib.suppress(sd.PortAudioError):
-            hostapi_list.current(sd.default.hostapi)
-            hostapi_list.event_generate('<<ComboboxSelected>>')
+            self.hostapi_list.current(sd.default.hostapi)
+            self.hostapi_list.event_generate('<<ComboboxSelected>>')
+
+    def update_device_list(self, *args):
+        hostapi = sd.query_hostapis(self.hostapi_list.current())
+        self.device_ids = [
+            idx
+            for idx in hostapi['devices']
+            if sd.query_devices(idx)['max_input_channels'] > 0]
+        self.device_list['values'] = [
+            sd.query_devices(idx)['name'] for idx in self.device_ids]
+        default = hostapi['default_input_device']
+        if default >= 0:
+            self.device_list.current(self.device_ids.index(default))
+
+    def validate(self):
+        self.result = self.device_ids[self.device_list.current()]
+        return True
 
 
 class RecGui(tk.Tk):
@@ -203,7 +200,8 @@
 
     def on_settings(self, *args):
         w = SettingsWindow(self, 'Settings')
-        self.create_stream(device=w.result)
+        if w.result is not None:
+            self.create_stream(device=w.result)
 
     def init_buttons(self):
         self.rec_button['text'] = 'record'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sounddevice-0.4.1/examples/rec_unlimited.py 
new/sounddevice-0.4.5/examples/rec_unlimited.py
--- old/sounddevice-0.4.1/examples/rec_unlimited.py     2020-07-15 
17:23:35.000000000 +0200
+++ new/sounddevice-0.4.5/examples/rec_unlimited.py     2022-07-19 
19:26:16.000000000 +0200
@@ -1,7 +1,8 @@
 #!/usr/bin/env python3
 """Create a recording with arbitrary duration.
 
-The soundfile module (https://PySoundFile.readthedocs.io/) has to be installed!
+The soundfile module (https://python-soundfile.readthedocs.io/)
+has to be installed!
 
 """
 import argparse
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sounddevice-0.4.1/examples/spectrogram.py 
new/sounddevice-0.4.5/examples/spectrogram.py
--- old/sounddevice-0.4.1/examples/spectrogram.py       2020-07-15 
17:23:35.000000000 +0200
+++ new/sounddevice-0.4.5/examples/spectrogram.py       2022-04-11 
23:18:43.000000000 +0200
@@ -66,7 +66,7 @@
         if char == '\t':
             bg, fg = fg, bg
         else:
-            gradient.append('\x1b[{};{}m{}'.format(fg, bg + 10, char))
+            gradient.append(f'\x1b[{fg};{bg + 10}m{char}')
 
 try:
     samplerate = sd.query_devices(args.device, 'input')['default_samplerate']
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sounddevice-0.4.1/examples/wire.py 
new/sounddevice-0.4.5/examples/wire.py
--- old/sounddevice-0.4.1/examples/wire.py      2020-07-15 17:23:35.000000000 
+0200
+++ new/sounddevice-0.4.5/examples/wire.py      2022-07-19 19:26:16.000000000 
+0200
@@ -1,7 +1,7 @@
 #!/usr/bin/env python3
 """Pass input directly to output.
 
-https://app.assembla.com/spaces/portaudio/git/source/master/test/patest_wire.c
+https://github.com/PortAudio/portaudio/blob/master/test/patest_wire.c
 
 """
 import argparse
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sounddevice-0.4.1/setup.py 
new/sounddevice-0.4.5/setup.py
--- old/sounddevice-0.4.1/setup.py      2020-07-15 17:23:35.000000000 +0200
+++ new/sounddevice-0.4.5/setup.py      2022-04-11 23:18:43.000000000 +0200
@@ -9,12 +9,9 @@
         exec(line)
         break
 
-PYTHON_INTERPRETERS = '.'.join([
-    'cp32', 'cp33', 'cp34', 'cp35', 'cp36', 'cp37', 'cp38', 'cp39',
-    'pp32', 'pp33', 'pp34', 'pp35', 'pp36', 'pp37',
-])
 MACOSX_VERSIONS = '.'.join([
-    'macosx_10_6_x86_64',
+    'macosx_10_6_x86_64',  # for compatibility with pip < v21
+    'macosx_10_6_universal2',
 ])
 
 # environment variables for cross-platform package creation
@@ -48,7 +45,6 @@
         """Create OS-dependent, but Python-independent wheels."""
 
         def get_tag(self):
-            pythons = 'py3.' + PYTHON_INTERPRETERS
             if system == 'Darwin':
                 oses = MACOSX_VERSIONS
             elif system == 'Windows':
@@ -57,9 +53,8 @@
                 else:
                     oses = 'win_amd64'
             else:
-                pythons = 'py3'
                 oses = 'any'
-            return pythons, 'none', oses
+            return 'py3', 'none', oses
 
     cmdclass = {'bdist_wheel': bdist_wheel_half_pure}
 
@@ -70,7 +65,7 @@
     packages=packages,
     package_data=package_data,
     zip_safe=zip_safe,
-    python_requires='>=3',
+    python_requires='>=3.7',
     setup_requires=['CFFI>=1.0'],
     install_requires=['CFFI>=1.0'],
     extras_require={'NumPy': ['NumPy']},
@@ -82,6 +77,9 @@
     license='MIT',
     keywords='sound audio PortAudio play record playrec'.split(),
     url='http://python-sounddevice.readthedocs.io/',
+    project_urls={
+        'Source': 'https://github.com/spatialaudio/python-sounddevice',
+    },
     platforms='any',
     classifiers=[
         'License :: OSI Approved :: MIT License',
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sounddevice-0.4.1/sounddevice.egg-info/PKG-INFO 
new/sounddevice-0.4.5/sounddevice.egg-info/PKG-INFO
--- old/sounddevice-0.4.1/sounddevice.egg-info/PKG-INFO 2020-09-26 
19:17:25.000000000 +0200
+++ new/sounddevice-0.4.5/sounddevice.egg-info/PKG-INFO 2022-08-21 
17:36:27.000000000 +0200
@@ -1,32 +1,12 @@
 Metadata-Version: 2.1
 Name: sounddevice
-Version: 0.4.1
+Version: 0.4.5
 Summary: Play and Record Sound with Python
 Home-page: http://python-sounddevice.readthedocs.io/
 Author: Matthias Geier
 Author-email: matthias.ge...@gmail.com
 License: MIT
-Description: Play and Record Sound with Python
-        =================================
-        
-        This Python_ module provides bindings for the PortAudio_ library and a 
few
-        convenience functions to play and record NumPy_ arrays containing 
audio signals.
-        
-        The ``sounddevice`` module is available for Linux, macOS and Windows.
-        
-        Documentation:
-           https://python-sounddevice.readthedocs.io/
-        
-        Source code repository and issue tracker:
-           https://github.com/spatialaudio/python-sounddevice/
-        
-        License:
-           MIT -- see the file ``LICENSE`` for details.
-        
-        .. _Python: https://www.python.org/
-        .. _PortAudio: http://www.portaudio.com/
-        .. _NumPy: https://numpy.org/
-        
+Project-URL: Source, https://github.com/spatialaudio/python-sounddevice
 Keywords: sound,audio,PortAudio,play,record,playrec
 Platform: any
 Classifier: License :: OSI Approved :: MIT License
@@ -34,5 +14,27 @@
 Classifier: Programming Language :: Python
 Classifier: Programming Language :: Python :: 3
 Classifier: Topic :: Multimedia :: Sound/Audio
-Requires-Python: >=3
+Requires-Python: >=3.7
 Provides-Extra: NumPy
+License-File: LICENSE
+
+Play and Record Sound with Python
+=================================
+
+This Python_ module provides bindings for the PortAudio_ library and a few
+convenience functions to play and record NumPy_ arrays containing audio 
signals.
+
+The ``sounddevice`` module is available for Linux, macOS and Windows.
+
+Documentation:
+   https://python-sounddevice.readthedocs.io/
+
+Source code repository and issue tracker:
+   https://github.com/spatialaudio/python-sounddevice/
+
+License:
+   MIT -- see the file ``LICENSE`` for details.
+
+.. _Python: https://www.python.org/
+.. _PortAudio: http://www.portaudio.com/
+.. _NumPy: https://numpy.org/
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sounddevice-0.4.1/sounddevice.egg-info/SOURCES.txt 
new/sounddevice-0.4.5/sounddevice.egg-info/SOURCES.txt
--- old/sounddevice-0.4.1/sounddevice.egg-info/SOURCES.txt      2020-09-26 
19:17:25.000000000 +0200
+++ new/sounddevice-0.4.5/sounddevice.egg-info/SOURCES.txt      2022-08-21 
17:36:27.000000000 +0200
@@ -29,6 +29,7 @@
 examples/asyncio_generators.py
 examples/play_file.py
 examples/play_long_file.py
+examples/play_long_file_raw.py
 examples/play_sine.py
 examples/play_stream.py
 examples/plot_input.py
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sounddevice-0.4.1/sounddevice.py 
new/sounddevice-0.4.5/sounddevice.py
--- old/sounddevice-0.4.1/sounddevice.py        2020-09-26 19:15:40.000000000 
+0200
+++ new/sounddevice-0.4.5/sounddevice.py        2022-08-21 17:21:44.000000000 
+0200
@@ -1,4 +1,4 @@
-# Copyright (c) 2015-2020 Matthias Geier
+# Copyright (c) 2015-2021 Matthias Geier
 #
 # Permission is hereby granted, free of charge, to any person obtaining a copy
 # of this software and associated documentation files (the "Software"), to deal
@@ -48,7 +48,7 @@
     https://python-sounddevice.readthedocs.io/
 
 """
-__version__ = '0.4.1'
+__version__ = '0.4.5'
 
 import atexit as _atexit
 import os as _os
@@ -113,7 +113,8 @@
     * Start the stream.
 
     * If ``blocking=True`` was given, wait until playback is done.
-      If not, return immediately.
+      If not, return immediately
+      (to start waiting at a later point, `wait()` can be used).
 
     If you need more control (e.g. block-wise gapless playback, multiple
     overlapping playbacks, ...), you should explicitly create an
@@ -195,7 +196,8 @@
     * Start the stream.
 
     * If ``blocking=True`` was given, wait until recording is done.
-      If not, return immediately.
+      If not, return immediately
+      (to start waiting at a later point, `wait()` can be used).
 
     If you need more control (e.g. block-wise gapless recording,
     overlapping recordings, ...), you should explicitly create an
@@ -292,7 +294,8 @@
     * Start the stream.
 
     * If ``blocking=True`` was given, wait until playback/recording is
-      done.  If not, return immediately.
+      done.  If not, return immediately
+      (to start waiting at a later point, `wait()` can be used).
 
     If you need more control (e.g. block-wise gapless playback and
     recording, realtime processing, ...),
@@ -476,6 +479,8 @@
 
         ``'name'``
             The name of the device.
+        ``'index'``
+            The device index.
         ``'hostapi'``
             The ID of the corresponding host API.  Use
             `query_hostapis()` to get information about a host API.
@@ -554,14 +559,14 @@
 
     """
     if kind not in ('input', 'output', None):
-        raise ValueError('Invalid kind: {!r}'.format(kind))
+        raise ValueError(f'Invalid kind: {kind!r}')
     if device is None and kind is None:
         return DeviceList(query_devices(i)
                           for i in range(_check(_lib.Pa_GetDeviceCount())))
     device = _get_device_id(device, kind, raise_on_error=True)
     info = _lib.Pa_GetDeviceInfo(device)
     if not info:
-        raise PortAudioError('Error querying device {}'.format(device))
+        raise PortAudioError(f'Error querying device {device}')
     assert info.structVersion == 2
     name_bytes = _ffi.string(info.name)
     try:
@@ -580,6 +585,7 @@
             raise
     device_dict = {
         'name': name,
+        'index': device,
         'hostapi': info.hostApi,
         'max_input_channels': info.maxInputChannels,
         'max_output_channels': info.maxOutputChannels,
@@ -637,7 +643,7 @@
                      for i in range(_check(_lib.Pa_GetHostApiCount())))
     info = _lib.Pa_GetHostApiInfo(index)
     if not info:
-        raise PortAudioError('Error querying host API {}'.format(index))
+        raise PortAudioError(f'Error querying host API {index}')
     assert info.structVersion == 1
     return {
         'name': _ffi.string(info.name).decode(),
@@ -713,7 +719,7 @@
     return _lib.Pa_GetVersion(), _ffi.string(_lib.Pa_GetVersionText()).decode()
 
 
-class _StreamBase(object):
+class _StreamBase:
     """Direct or indirect base class for all stream classes."""
 
     def __init__(self, kind, samplerate=None, blocksize=None, device=None,
@@ -892,7 +898,7 @@
         _check(_lib.Pa_OpenStream(self._ptr, iparameters, oparameters,
                                   samplerate, blocksize, stream_flags,
                                   callback_ptr, userdata),
-               'Error opening {}'.format(self.__class__.__name__))
+               f'Error opening {self.__class__.__name__}')
 
         # dereference PaStream** --> PaStream*
         self._ptr = self._ptr[0]
@@ -1524,8 +1530,12 @@
         data = np.asarray(data)
         _, dtype = _split(self._dtype)
         _, channels = _split(self._channels)
-        if data.ndim > 1 and data.shape[1] != channels:
-            raise ValueError('Number of channels must match')
+        if data.ndim < 2:
+            data = data.reshape(-1, 1)
+        elif data.ndim > 2:
+            raise ValueError('data must be one- or two-dimensional')
+        if data.shape[1] != channels:
+            raise ValueError('number of channels must match')
         if data.dtype != dtype:
             raise TypeError('dtype mismatch: {!r} vs {!r}'.format(
                 data.dtype.name, dtype))
@@ -1605,6 +1615,10 @@
             Device index(es) or query string(s) specifying the device(s)
             to be used.  The default value(s) can be changed with
             `default.device`.
+            If a string is given, the device is selected which contains
+            all space-separated parts in the right order.  Each device
+            string contains the name of the corresponding host API in
+            the end.  The string comparison is case-insensitive.
         channels : int or pair of int, optional
             The number of channels of sound to be delivered to the
             stream callback or accessed by `read()` or `write()`.  It
@@ -1624,20 +1638,30 @@
             The packed 24 bit format ``'int24'`` is only supported in
             the "raw" stream classes, see `RawStream`.  The default
             value(s) can be changed with `default.dtype`.
+            If NumPy is available, the corresponding `numpy.dtype`
+            objects can be used as well.  The floating point
+            representations ``'float32'`` and ``'float64'`` use ``+1.0``
+            and ``-1.0`` as the maximum and minimum values,
+            respectively.  ``'uint8'`` is an unsigned 8 bit format where
+            ``128`` is considered "ground".
         latency : float or {'low', 'high'} or pair thereof, optional
             The desired latency in seconds.  The special values
             ``'low'`` and ``'high'`` (latter being the default) select
-            the default low and high latency, respectively (see
-            `query_devices()`).  The default value(s) can be changed
-            with `default.latency`.
-            Where practical, implementations should configure their
-            latency based on this parameter, otherwise they may choose
-            the closest viable latency instead.  Unless the suggested
-            latency is greater than the absolute upper limit for the
-            device, implementations should round the *latency* up to the
-            next practical value -- i.e. to provide an equal or higher
-            latency  wherever possible.  Actual latency values for an
-            open stream may be retrieved using the `latency` attribute.
+            the device's default low and high latency, respectively (see
+            `query_devices()`).  ``'high'`` is typically more robust
+            (i.e. buffer under-/overflows are less likely),
+            but the latency may be too large for interactive applications.
+
+            .. note:: Specifying the desired latency as ``'high'`` does
+                not *guarantee* a stable audio stream. For reference, by
+                default Audacity_ specifies a desired latency of ``0.1``
+                seconds and typically achieves robust performance.
+
+            .. _Audacity: https://www.audacityteam.org/
+
+            The default value(s) can be changed with `default.latency`.
+            Actual latency values for an open stream can be retrieved
+            using the `latency` attribute.
         extra_settings : settings object or pair thereof, optional
             This can be used for host-API-specific input/output
             settings.  See `default.extra_settings`.
@@ -1801,7 +1825,7 @@
         digits = len(str(_lib.Pa_GetDeviceCount() - 1))
         hostapi_names = [hostapi['name'] for hostapi in query_hostapis()]
         text = '\n'.join(
-            u'{mark} {idx:{dig}} {name}, {ha} ({ins} in, {outs} out)'.format(
+            '{mark} {idx:{dig}} {name}, {ha} ({ins} in, {outs} out)'.format(
                 mark=(' ', '>', '<', '*')[(idx == idev) + 2 * (idx == odev)],
                 idx=idx,
                 dig=digits,
@@ -1813,7 +1837,7 @@
         return text
 
 
-class CallbackFlags(object):
+class CallbackFlags:
     """Flag bits for the *status* argument to a stream *callback*.
 
     If you experience under-/overflows, you can try to increase the
@@ -1863,7 +1887,7 @@
         flags = str(self)
         if not flags:
             flags = 'no flags set'
-        return '<sounddevice.CallbackFlags: {}>'.format(flags)
+        return f'<sounddevice.CallbackFlags: {flags}>'
 
     def __str__(self):
         return ', '.join(name.replace('_', ' ') for name in dir(self)
@@ -1981,7 +2005,7 @@
             self._flags &= ~flag
 
 
-class _InputOutputPair(object):
+class _InputOutputPair:
     """Parameter pairs for device, channels, dtype and latency."""
 
     _indexmapping = {'input': 0, 'output': 1}
@@ -2006,7 +2030,7 @@
         return '[{0[0]!r}, {0[1]!r}]'.format(self)
 
 
-class default(object):
+class default:
     """Get/set defaults for the *sounddevice* module.
 
     The attributes `device`, `channels`, `dtype`, `latency` and
@@ -2051,12 +2075,9 @@
     device = None, None
     """Index or query string of default input/output device.
 
-    If not overwritten, this is queried from PortAudio.
+    See the *device* argument of `Stream`.
 
-    If a string is given, the device is selected which contains all
-    space-separated parts in the right order.  Each device string
-    contains the name of the corresponding host API in the end.
-    The string comparison is case-insensitive.
+    If not overwritten, this is queried from PortAudio.
 
     See Also
     --------
@@ -2064,14 +2085,19 @@
 
     """
     channels = _default_channels = None, None
-    """Number of input/output channels.
+    """Default number of input/output channels.
+
+    See the *channels* argument of `Stream`.
 
-    The maximum number of channels for a given device can be found out
-    with `query_devices()`.
+    See Also
+    --------
+    :func:`query_devices`
 
     """
     dtype = _default_dtype = 'float32', 'float32'
-    """Data type used for input/output samples.
+    """Default data type used for input/output samples.
+
+    See the *dtype* argument of `Stream`.
 
     The types ``'float32'``, ``'int32'``, ``'int16'``, ``'int8'`` and
     ``'uint8'`` can be used for all streams and functions.
@@ -2081,29 +2107,9 @@
     `RawStream` support ``'int24'`` (packed 24 bit format, which is
     *not* supported in NumPy!).
 
-    If NumPy is available, the corresponding `numpy.dtype` objects can
-    be used as well.
-
-    The floating point representations ``'float32'`` and ``'float64'``
-    use +1.0 and -1.0 as the maximum and minimum values, respectively.
-    ``'uint8'`` is an unsigned 8 bit format where 128 is considered
-    "ground".
-
     """
     latency = _default_latency = 'high', 'high'
-    """Suggested input/output latency in seconds.
-
-    The special values ``'low'`` and ``'high'`` can be used to select
-    the default low/high latency of the chosen device.
-    ``'high'`` is typically more robust (i.e. buffer under-/overflows
-    are less likely), but the latency may be too large for interactive
-    applications.
-
-    See Also
-    --------
-    :func:`query_devices`
-
-    """
+    """See the *latency* argument of `Stream`."""
     extra_settings = _default_extra_settings = None, None
     """Host-API-specific input/output settings.
 
@@ -2214,7 +2220,7 @@
     def __str__(self):
         errormsg = self.args[0] if self.args else ''
         if len(self.args) > 1:
-            errormsg = '{} [PaErrorCode {}]'.format(errormsg, self.args[1])
+            errormsg = f'{errormsg} [PaErrorCode {self.args[1]}]'
         if len(self.args) > 2:
             host_api, hosterror_code, hosterror_text = self.args[2]
             hostname = query_hostapis(host_api)['name']
@@ -2250,7 +2256,7 @@
     """
 
 
-class AsioSettings(object):
+class AsioSettings:
 
     def __init__(self, channel_selectors):
         """ASIO-specific input/output settings.
@@ -2302,7 +2308,7 @@
             channelSelectors=self._selectors))
 
 
-class CoreAudioSettings(object):
+class CoreAudioSettings:
 
     def __init__(self, channel_map=None, change_device_parameters=False,
                  fail_if_conversion_required=False, conversion_quality='max'):
@@ -2394,7 +2400,7 @@
                                            len(self._channel_map))
 
 
-class WasapiSettings(object):
+class WasapiSettings:
 
     def __init__(self, exclusive=False):
         """WASAPI-specific input/output settings.
@@ -2435,7 +2441,7 @@
         ))
 
 
-class _CallbackContext(object):
+class _CallbackContext:
     """Helper class for re-use in play()/rec()/playrec() callbacks."""
 
     blocksize = None
@@ -2465,6 +2471,9 @@
         data = np.asarray(data)
         if data.ndim < 2:
             data = data.reshape(-1, 1)
+        elif data.ndim > 2:
+            raise ValueError(
+                'audio data to be played back must be one- or two-dimensional')
         frames, channels = data.shape
         dtype = _check_dtype(data.dtype)
         mapping_is_explicit = mapping is not None
@@ -2722,7 +2731,7 @@
 
     errormsg = _ffi.string(_lib.Pa_GetErrorText(err)).decode()
     if msg:
-        errormsg = '{}: {}'.format(msg, errormsg)
+        errormsg = f'{msg}: {errormsg}'
 
     if err == _lib.paUnanticipatedHostError:
         # (gh82) We grab the host error info here rather than inside
@@ -2779,7 +2788,7 @@
             pos += len(substring)
         else:
             matches.append((id, full_string))
-            if device_string.lower() == query_string:
+            if query_string in [device_string.lower(), full_string.lower()]:
                 exact_device_matches.append(id)
 
     if kind is None:
@@ -2797,7 +2806,7 @@
         if raise_on_error:
             raise ValueError('Multiple ' + kind + ' devices found for ' +
                              repr(id_or_query_string) + ':\n' +
-                             '\n'.join('[{}] {}'.format(id, name)
+                             '\n'.join(f'[{id}] {name}'
                                        for id, name in matches))
         else:
             return -1
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sounddevice-0.4.1/sounddevice_build.py 
new/sounddevice-0.4.5/sounddevice_build.py
--- old/sounddevice-0.4.1/sounddevice_build.py  2020-07-15 17:23:35.000000000 
+0200
+++ new/sounddevice-0.4.5/sounddevice_build.py  2022-03-03 20:40:29.000000000 
+0100
@@ -307,6 +307,8 @@
     PaWasapiStreamCategory streamCategory;
     PaWasapiStreamOption streamOption;
 } PaWasapiStreamInfo;
+
+int PaWasapi_IsLoopback( PaDeviceIndex device );
 """)
 
 ffibuilder.cdef("""

Reply via email to