SoundCard


NameSoundCard JSON
Version 0.4.3 PyPI version JSON
download
home_pagehttps://github.com/bastibe/SoundCard
SummaryPlay and record audio without resorting to CPython extensions
upload_time2024-03-19 16:23:18
maintainer
docs_urlNone
authorBastian Bechtold
requires_python>=3.5
licenseBSD 3-clause
keywords
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            SoundCard
=========

|version| |python| |status| |license|

|contributors| |downloads|

SoundCard is a library for playing and recording audio without resorting to a
CPython extension. Instead, it is implemented using the wonderful `CFFI
<http://cffi.readthedocs.io/en/latest/>`__ and the native audio libraries of
Linux, Windows and macOS.

The input and output data are scaled to 0dBFS (Full Scale). To avoid clipping  
restrict all data between -1 and 1.

SoundCard is cross-platform, and supports Linux/pulseaudio, Mac/coreaudio, and
Windows/WASAPI. While the programming interface is identical across platforms,
sound card naming schemes and default block sizes can vary between devices and
platforms. 

SoundCard is still in development. All major features work on all platforms, but
there are a few known issues that still need to be fixed. If you find a bug,
please open an Issue, and I will try to fix it. Or open a Pull Request, and I
will try to include your fix into SoundCard.

However, please be aware that this is a hobby project of mine that I am
developing for free, and in my spare time. While I try to be as accomodating as
possible, I can not guarantee a timely response to issues. Publishing Open
Source Software on Github does not imply an obligation to *fix your problem
right now*. Please be civil.

| SoundCard is licensed under the terms of the BSD 3-clause license
| (c) 2016 Bastian Bechtold


|open-issues| |closed-issues| |open-prs| |closed-prs|

.. |status| image:: https://img.shields.io/pypi/status/soundcard.svg
.. |contributors| image:: https://img.shields.io/github/contributors/bastibe/soundcard.svg
.. |version| image:: https://img.shields.io/pypi/v/soundcard.svg
.. |python| image:: https://img.shields.io/pypi/pyversions/soundcard.svg
.. |license| image:: https://img.shields.io/github/license/bastibe/soundcard.svg
.. |downloads| image:: https://img.shields.io/pypi/dm/soundcard.svg
.. |open-issues| image:: https://img.shields.io/github/issues/bastibe/soundcard.svg
.. |closed-issues| image:: https://img.shields.io/github/issues-closed/bastibe/soundcard.svg
.. |open-prs| image:: https://img.shields.io/github/issues-pr/bastibe/soundcard.svg
.. |closed-prs| image:: https://img.shields.io/github/issues-pr-closed/bastibe/soundcard.svg

Tutorial
--------

Here is how you get to your Speakers and Microphones:

.. code:: python

    import soundcard as sc

    # get a list of all speakers:
    speakers = sc.all_speakers()
    # get the current default speaker on your system:
    default_speaker = sc.default_speaker()
    # get a list of all microphones:
    mics = sc.all_microphones()
    # get the current default microphone on your system:
    default_mic = sc.default_microphone()

    # search for a sound card by substring:
    >>> sc.get_speaker('Scarlett')
    <Speaker Focusrite Scarlett 2i2 (2 channels)>
    >>> one_mic = sc.get_microphone('Scarlett')
    <Microphone Focusrite Scalett 2i2 (2 channels)>
    # fuzzy-search to get the same results:
    one_speaker = sc.get_speaker('FS2i2')
    one_mic = sc.get_microphone('FS2i2')


All of these functions return ``Speaker`` and ``Microphone`` objects, which can
be used for playback and recording. All data passed in and out of these objects
are *frames × channels* Numpy arrays.

.. code:: python

    import numpy

    >>> print(default_speaker)
    <Speaker Focusrite Scarlett 2i2 (2 channels)>
    >>> print(default_mic)
    <Microphone Focusrite Scarlett 2i2 (2 channels)>

    # record and play back one second of audio:
    data = default_mic.record(samplerate=48000, numframes=48000)
    # normalized playback
    default_speaker.play(data/numpy.max(numpy.abs(data)), samplerate=48000)

    # alternatively, get a `Recorder` and `Player` object
    # and play or record continuously:
    with default_mic.recorder(samplerate=48000) as mic, \
          default_speaker.player(samplerate=48000) as sp:
        for _ in range(100):
            data = mic.record(numframes=1024)
            sp.play(data)

Latency
-------

By default, SoundCard records and plays at the operating system's default
configuration. Particularly on laptops, this configuration might have extreme
latencies, up to multiple seconds.

In order to request lower latencies, pass a ``blocksize`` to ``player`` or
``recorder``. This tells the operating system your desired latency, and it will
try to honor your request as best it can. On Windows/WASAPI, setting
``exclusive_mode=True`` might help, too (this is currently experimental).

Another source of latency is in the ``record`` function, which buffers output up
to the requested ``numframes``. In general, for optimal latency, you should use
a ``numframes`` significantly lower than the ``blocksize`` above, maybe by a
factor of two or four.

To get the audio data as quickly as absolutely possible, you can use
``numframes=None``, which will return whatever audio data is available right
now, without any buffering. Note that this might receive different numbers of
frames each time.

With the above settings, block sizes of 256 samples or ten milliseconds are
usually no problem. The total latency of playback and recording is dependent on
how these buffers are handled by the operating system, though, and might be
significantly higher.

Additionally, it might help to experiment with advice from here: https://askubuntu.com/questions/707171/how-can-i-fix-choppy-audio and edit your /etc/pulse/default.pa file to replace the line saying ::

    load-module module-udev-detect

with ::

    load-module module-udev-detect tsched=0

and then do not forget to restart pulseaudio with ::

    pulseaudio -k


Channel Maps
------------

Some professional sound cards have large numbers of channels. If you want to
record or play only a subset of those channels, you can specify a channel map.
A channel map consists of a list of channel specifiers, which refer to the
channels of the audio backend in use. The index of each of those specifiers
in the the channel map list indicates the channel index in the numpy data array
used in SoundCard:

.. code:: python

    # record one second of audio from backend channels 0 to 3:
    data = default_mic.record(samplerate=48000, channels=[0, 1, 2, 3], numframes=48000)

    # play back the recorded audio in reverse channel order:
    default_speaker.play(data=data, channels=[3, 2, 1, 0], samplerate=48000)


The meaning of the channel specifiers depend on the backend in use. For WASAPI
(Windows) and CoreAudio (macOS) the indices refer to the physical output
channels of the sound device in use. For the PulseAudio backend (Linux) the
specifiers refer to logical channel positions instead of physical hardware
channels.

The channel position identifiers in the PulseAudio backend are based on:
https://freedesktop.org/software/pulseaudio/doxygen/channelmap_8h.html
Since the mapping of position indices to audio channels is not obvious, a
dictionary containing all possible positions and channel indices can be
retrieved by calling ``channel_name_map()``. The positions for the indices up to 10 are: ::

    'mono': -1,
    'left': 0,
    'right': 1,
    'center': 2,
    'rear-center': 3,
    'rear-left': 4,
    'rear-right': 5,
    'lfe': 6,
    'front-left-of-center': 7,
    'front-right-of-center': 8,
    'side-left': 9,
    'side-right': 10

The identifier ``mono`` or the index ``-1`` can be used for mono mix of all
channels for both playback and recording. (CoreAudio/macOS defines channel ``-1``
as silence for both playback and recording.) In addition to the indices, the PulseAudio
backend allows the use of the name strings to define a channel map:

.. code:: python

    # This example plays one second of noise on each channel defined in the channel map consecutively.
    # The channel definition scheme using strings only works with the PulseAudio backend!

    # This defines a channel map for a 7.1 audio sink device
    channel_map = ['left', 'right', 'center', 'lfe', 'rear-left', 'rear-right', 'side-left', 'side-right']

    num_channels = len(channel_map)
    samplerate = 48000

    # Create the multi channel noise array.
    noise_samples = 48000
    noise = numpy.random.uniform(-0.1, 0.1, noise_samples)
    data = numpy.zeros((num_channels * noise_samples, num_channels), dtype=numpy.float32)
    for channel in range(num_channels):
        data[channel * noise_samples:(channel + 1) * noise_samples, channel] = noise

    # Playback using the 7.1 channel map.
    default_speaker.play(data=data, channels=channel_map, samplerate=samplerate)

The available channels of each PulseAudio source or sink can be listed by ::

    > pactl list sinks
    > pactl list sources


The ``Channel Map`` property lists the channel identifier of the source/sink. ::

    > pactl list sinks | grep  "Channel Map" -B 6
    
    Sink #486
        State: SUSPENDED
        Name: alsa_output.usb-C-Media_Electronics_Inc._USB_Advanced_Audio_Device-00.analog-stereo
        Description: USB Advanced Audio Device Analog Stereo
        Driver: PipeWire
        Sample Specification: s24le 2ch 48000Hz
        Channel Map: front-left,front-right
    --
    Sink #488
            State: RUNNING
            Name: alsa_output.pci-0000_2f_00.4.analog-surround-71
            Description: Starship/Matisse HD Audio Controller Analog Surround 7.1
            Driver: PipeWire
            Sample Specification: s32le 8ch 48000Hz
            Channel Map: front-left,front-right,rear-left,rear-right,front-center,lfe,side-left,side-right


FAQ
---
Q: How to make it work on a headless Raspberry Pi?

A: PulseAudio is not installed by default on the Raspberry Pi OS Lite distribution (https://www.raspberrypi.org/software/operating-systems/). In order to use ``soundcard``, you have to install PulseAudio first, and edit the configuration (with a fix to avoid the main output to be in mono-only). ::

    sudo apt install -y python3-pip python3-numpy pulseaudio
    sudo nano /usr/share/pulseaudio/alsa-mixer/profile-sets/default.conf
    # comment the block [Mapping analog-mono] with ';'
    pulseaudio -D
    python3 -m pip install soundcard


Known Issues:
-------------

* Windows/WASAPI currently records garbage if you record only a single channel.
  The reason for this is yet unknown. Multi-channel and channel maps work,
  though.
* Windows/WASAPI silently ignores the blocksize in some cases. Apparently, it
  only supports variable block sizes in exclusive mode.
* Windows/WASAPI may underrun its buffers even if blocksize and nframes are
  matched. Use a larger blocksize than nframes if this happens.
* Error messages often report some internal CFFI/backend errors. This will be
  improved in the future.
* macOS Records silence happens when you run your script with an app that doesn't
  ask for microphone permission to solve it, go to settings and give microphone
  permission to the app you are running the script.

Changelog
---------

- 2018-04-25 implements fixed block sizes when recording
  (thank you, Pariente Manuel!)
- 2018-05-10 adds a test suite and various fixes for Windows
- 2018-05-11 various fixes for macOS
- 2018-06-27 Adds latency property to Linux/pulseaudio
  (Thank you, Pariente Manuel!)
- 2018-07-17 adds loopback support for Windows
  (Thank you, Jan Leskovec!)
- 2018-10-16 adds bug fix for IPython on Windows
  (Thank you, Sebastian Michel!)
- 2018-11-28 adds Sphinx/Readthedocs documentation
- 2019-03-25 adds support for Python 3.5
  (Thank you, Daniel R. Kumor!)
- 2019-04-29 adds experimental support for exclusive mode on Windows
- 2019-05-13 fixes sample rate conversion on macOS
- 2019-05-15 fixes silence recording on macOS
- 2019-06-11 fixes exception when monitoring default device on Linux
  (Thank you, Inti Pelupessy!)
- 2019-06-18 fixes crash when opening many streams on Linux
- 2019-08-23 fixes attribute error when accessing stream state on Linux
  (Thank you, Davíð Sindri Pétursson!)
- 2019-10-08 fixes inconsistent dtypes when recording on Linux
- 2020-01-06 fixes silent recordings on Windows
- 2020-04-28 get and set the pulseaudio program name on Linux
  (Thank you, Philipp A.!)
- 2020-05-14 fixes error with unicode soundcard names on Windows
  (Thank you, BAKEZQ!)
- 2020-05-18 adds support for pyinstaller (v4)
  (Thank you, Bob Thomas!)
- 2020-05-19 adds compatibility with Windows 7
  (Thank you, demberto!)
- 2020-07-22 fixes freezing bug on Linux during startup
  (Thank you, zhujisheng!)
- 2020-08-01 improves error reporting on Linux
  (Thank you, Rik van Riel!)
- 2020-08-13 fixes crash due to use-after-free on Linux
  (Thank you, Rik van Riel!)
- 2021-01-13 fixes unicode error on Windows
  (Thank you, paulzzh!)
- 2021-11-24 adds compatibility with NixOS library naming
  (Thank you, shithead!)
- 2021-12-23 fixes deprecation for Python 3.10
  (Thank you, Nekyo!)
- 2022-04-29 fixes deprecation in recent Numpy
- 2024-03-16 fixes empty soundcard list on macOS
  (Thank you, Patrice Brend'amour!)

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/bastibe/SoundCard",
    "name": "SoundCard",
    "maintainer": "",
    "docs_url": null,
    "requires_python": ">=3.5",
    "maintainer_email": "",
    "keywords": "",
    "author": "Bastian Bechtold",
    "author_email": "",
    "download_url": "https://files.pythonhosted.org/packages/fe/61/8fa850aacd49ad4c838cb51cd8893c1696ac32693efc22640f39f8190d50/SoundCard-0.4.3.tar.gz",
    "platform": null,
    "description": "SoundCard\n=========\n\n|version| |python| |status| |license|\n\n|contributors| |downloads|\n\nSoundCard is a library for playing and recording audio without resorting to a\nCPython extension. Instead, it is implemented using the wonderful `CFFI\n<http://cffi.readthedocs.io/en/latest/>`__ and the native audio libraries of\nLinux, Windows and macOS.\n\nThe input and output data are scaled to 0dBFS (Full Scale). To avoid clipping  \nrestrict all data between -1 and 1.\n\nSoundCard is cross-platform, and supports Linux/pulseaudio, Mac/coreaudio, and\nWindows/WASAPI. While the programming interface is identical across platforms,\nsound card naming schemes and default block sizes can vary between devices and\nplatforms. \n\nSoundCard is still in development. All major features work on all platforms, but\nthere are a few known issues that still need to be fixed. If you find a bug,\nplease open an Issue, and I will try to fix it. Or open a Pull Request, and I\nwill try to include your fix into SoundCard.\n\nHowever, please be aware that this is a hobby project of mine that I am\ndeveloping for free, and in my spare time. While I try to be as accomodating as\npossible, I can not guarantee a timely response to issues. Publishing Open\nSource Software on Github does not imply an obligation to *fix your problem\nright now*. Please be civil.\n\n| SoundCard is licensed under the terms of the BSD 3-clause license\n| (c) 2016 Bastian Bechtold\n\n\n|open-issues| |closed-issues| |open-prs| |closed-prs|\n\n.. |status| image:: https://img.shields.io/pypi/status/soundcard.svg\n.. |contributors| image:: https://img.shields.io/github/contributors/bastibe/soundcard.svg\n.. |version| image:: https://img.shields.io/pypi/v/soundcard.svg\n.. |python| image:: https://img.shields.io/pypi/pyversions/soundcard.svg\n.. |license| image:: https://img.shields.io/github/license/bastibe/soundcard.svg\n.. |downloads| image:: https://img.shields.io/pypi/dm/soundcard.svg\n.. |open-issues| image:: https://img.shields.io/github/issues/bastibe/soundcard.svg\n.. |closed-issues| image:: https://img.shields.io/github/issues-closed/bastibe/soundcard.svg\n.. |open-prs| image:: https://img.shields.io/github/issues-pr/bastibe/soundcard.svg\n.. |closed-prs| image:: https://img.shields.io/github/issues-pr-closed/bastibe/soundcard.svg\n\nTutorial\n--------\n\nHere is how you get to your Speakers and Microphones:\n\n.. code:: python\n\n    import soundcard as sc\n\n    # get a list of all speakers:\n    speakers = sc.all_speakers()\n    # get the current default speaker on your system:\n    default_speaker = sc.default_speaker()\n    # get a list of all microphones:\n    mics = sc.all_microphones()\n    # get the current default microphone on your system:\n    default_mic = sc.default_microphone()\n\n    # search for a sound card by substring:\n    >>> sc.get_speaker('Scarlett')\n    <Speaker Focusrite Scarlett 2i2 (2 channels)>\n    >>> one_mic = sc.get_microphone('Scarlett')\n    <Microphone Focusrite Scalett 2i2 (2 channels)>\n    # fuzzy-search to get the same results:\n    one_speaker = sc.get_speaker('FS2i2')\n    one_mic = sc.get_microphone('FS2i2')\n\n\nAll of these functions return ``Speaker`` and ``Microphone`` objects, which can\nbe used for playback and recording. All data passed in and out of these objects\nare *frames \u00d7 channels* Numpy arrays.\n\n.. code:: python\n\n    import numpy\n\n    >>> print(default_speaker)\n    <Speaker Focusrite Scarlett 2i2 (2 channels)>\n    >>> print(default_mic)\n    <Microphone Focusrite Scarlett 2i2 (2 channels)>\n\n    # record and play back one second of audio:\n    data = default_mic.record(samplerate=48000, numframes=48000)\n    # normalized playback\n    default_speaker.play(data/numpy.max(numpy.abs(data)), samplerate=48000)\n\n    # alternatively, get a `Recorder` and `Player` object\n    # and play or record continuously:\n    with default_mic.recorder(samplerate=48000) as mic, \\\n          default_speaker.player(samplerate=48000) as sp:\n        for _ in range(100):\n            data = mic.record(numframes=1024)\n            sp.play(data)\n\nLatency\n-------\n\nBy default, SoundCard records and plays at the operating system's default\nconfiguration. Particularly on laptops, this configuration might have extreme\nlatencies, up to multiple seconds.\n\nIn order to request lower latencies, pass a ``blocksize`` to ``player`` or\n``recorder``. This tells the operating system your desired latency, and it will\ntry to honor your request as best it can. On Windows/WASAPI, setting\n``exclusive_mode=True`` might help, too (this is currently experimental).\n\nAnother source of latency is in the ``record`` function, which buffers output up\nto the requested ``numframes``. In general, for optimal latency, you should use\na ``numframes`` significantly lower than the ``blocksize`` above, maybe by a\nfactor of two or four.\n\nTo get the audio data as quickly as absolutely possible, you can use\n``numframes=None``, which will return whatever audio data is available right\nnow, without any buffering. Note that this might receive different numbers of\nframes each time.\n\nWith the above settings, block sizes of 256 samples or ten milliseconds are\nusually no problem. The total latency of playback and recording is dependent on\nhow these buffers are handled by the operating system, though, and might be\nsignificantly higher.\n\nAdditionally, it might help to experiment with advice from here: https://askubuntu.com/questions/707171/how-can-i-fix-choppy-audio and edit your /etc/pulse/default.pa file to replace the line saying ::\n\n    load-module module-udev-detect\n\nwith ::\n\n    load-module module-udev-detect tsched=0\n\nand then do not forget to restart pulseaudio with ::\n\n    pulseaudio -k\n\n\nChannel Maps\n------------\n\nSome professional sound cards have large numbers of channels. If you want to\nrecord or play only a subset of those channels, you can specify a channel map.\nA channel map consists of a list of channel specifiers, which refer to the\nchannels of the audio backend in use. The index of each of those specifiers\nin the the channel map list indicates the channel index in the numpy data array\nused in SoundCard:\n\n.. code:: python\n\n    # record one second of audio from backend channels 0 to 3:\n    data = default_mic.record(samplerate=48000, channels=[0, 1, 2, 3], numframes=48000)\n\n    # play back the recorded audio in reverse channel order:\n    default_speaker.play(data=data, channels=[3, 2, 1, 0], samplerate=48000)\n\n\nThe meaning of the channel specifiers depend on the backend in use. For WASAPI\n(Windows) and CoreAudio (macOS) the indices refer to the physical output\nchannels of the sound device in use. For the PulseAudio backend (Linux) the\nspecifiers refer to logical channel positions instead of physical hardware\nchannels.\n\nThe channel position identifiers in the PulseAudio backend are based on:\nhttps://freedesktop.org/software/pulseaudio/doxygen/channelmap_8h.html\nSince the mapping of position indices to audio channels is not obvious, a\ndictionary containing all possible positions and channel indices can be\nretrieved by calling ``channel_name_map()``. The positions for the indices up to 10 are: ::\n\n    'mono': -1,\n    'left': 0,\n    'right': 1,\n    'center': 2,\n    'rear-center': 3,\n    'rear-left': 4,\n    'rear-right': 5,\n    'lfe': 6,\n    'front-left-of-center': 7,\n    'front-right-of-center': 8,\n    'side-left': 9,\n    'side-right': 10\n\nThe identifier ``mono`` or the index ``-1`` can be used for mono mix of all\nchannels for both playback and recording. (CoreAudio/macOS defines channel ``-1``\nas silence for both playback and recording.) In addition to the indices, the PulseAudio\nbackend allows the use of the name strings to define a channel map:\n\n.. code:: python\n\n    # This example plays one second of noise on each channel defined in the channel map consecutively.\n    # The channel definition scheme using strings only works with the PulseAudio backend!\n\n    # This defines a channel map for a 7.1 audio sink device\n    channel_map = ['left', 'right', 'center', 'lfe', 'rear-left', 'rear-right', 'side-left', 'side-right']\n\n    num_channels = len(channel_map)\n    samplerate = 48000\n\n    # Create the multi channel noise array.\n    noise_samples = 48000\n    noise = numpy.random.uniform(-0.1, 0.1, noise_samples)\n    data = numpy.zeros((num_channels * noise_samples, num_channels), dtype=numpy.float32)\n    for channel in range(num_channels):\n        data[channel * noise_samples:(channel + 1) * noise_samples, channel] = noise\n\n    # Playback using the 7.1 channel map.\n    default_speaker.play(data=data, channels=channel_map, samplerate=samplerate)\n\nThe available channels of each PulseAudio source or sink can be listed by ::\n\n    > pactl list sinks\n    > pactl list sources\n\n\nThe ``Channel Map`` property lists the channel identifier of the source/sink. ::\n\n    > pactl list sinks | grep  \"Channel Map\" -B 6\n    \n    Sink #486\n        State: SUSPENDED\n        Name: alsa_output.usb-C-Media_Electronics_Inc._USB_Advanced_Audio_Device-00.analog-stereo\n        Description: USB Advanced Audio Device Analog Stereo\n        Driver: PipeWire\n        Sample Specification: s24le 2ch 48000Hz\n        Channel Map: front-left,front-right\n    --\n    Sink #488\n            State: RUNNING\n            Name: alsa_output.pci-0000_2f_00.4.analog-surround-71\n            Description: Starship/Matisse HD Audio Controller Analog Surround 7.1\n            Driver: PipeWire\n            Sample Specification: s32le 8ch 48000Hz\n            Channel Map: front-left,front-right,rear-left,rear-right,front-center,lfe,side-left,side-right\n\n\nFAQ\n---\nQ: How to make it work on a headless Raspberry Pi?\n\nA: PulseAudio is not installed by default on the Raspberry Pi OS Lite distribution (https://www.raspberrypi.org/software/operating-systems/). In order to use ``soundcard``, you have to install PulseAudio first, and edit the configuration (with a fix to avoid the main output to be in mono-only). ::\n\n    sudo apt install -y python3-pip python3-numpy pulseaudio\n    sudo nano /usr/share/pulseaudio/alsa-mixer/profile-sets/default.conf\n    # comment the block [Mapping analog-mono] with ';'\n    pulseaudio -D\n    python3 -m pip install soundcard\n\n\nKnown Issues:\n-------------\n\n* Windows/WASAPI currently records garbage if you record only a single channel.\n  The reason for this is yet unknown. Multi-channel and channel maps work,\n  though.\n* Windows/WASAPI silently ignores the blocksize in some cases. Apparently, it\n  only supports variable block sizes in exclusive mode.\n* Windows/WASAPI may underrun its buffers even if blocksize and nframes are\n  matched. Use a larger blocksize than nframes if this happens.\n* Error messages often report some internal CFFI/backend errors. This will be\n  improved in the future.\n* macOS Records silence happens when you run your script with an app that doesn't\n  ask for microphone permission to solve it, go to settings and give microphone\n  permission to the app you are running the script.\n\nChangelog\n---------\n\n- 2018-04-25 implements fixed block sizes when recording\n  (thank you, Pariente Manuel!)\n- 2018-05-10 adds a test suite and various fixes for Windows\n- 2018-05-11 various fixes for macOS\n- 2018-06-27 Adds latency property to Linux/pulseaudio\n  (Thank you, Pariente Manuel!)\n- 2018-07-17 adds loopback support for Windows\n  (Thank you, Jan Leskovec!)\n- 2018-10-16 adds bug fix for IPython on Windows\n  (Thank you, Sebastian Michel!)\n- 2018-11-28 adds Sphinx/Readthedocs documentation\n- 2019-03-25 adds support for Python 3.5\n  (Thank you, Daniel R. Kumor!)\n- 2019-04-29 adds experimental support for exclusive mode on Windows\n- 2019-05-13 fixes sample rate conversion on macOS\n- 2019-05-15 fixes silence recording on macOS\n- 2019-06-11 fixes exception when monitoring default device on Linux\n  (Thank you, Inti Pelupessy!)\n- 2019-06-18 fixes crash when opening many streams on Linux\n- 2019-08-23 fixes attribute error when accessing stream state on Linux\n  (Thank you, Dav\u00ed\u00f0 Sindri P\u00e9tursson!)\n- 2019-10-08 fixes inconsistent dtypes when recording on Linux\n- 2020-01-06 fixes silent recordings on Windows\n- 2020-04-28 get and set the pulseaudio program name on Linux\n  (Thank you, Philipp A.!)\n- 2020-05-14 fixes error with unicode soundcard names on Windows\n  (Thank you, BAKEZQ!)\n- 2020-05-18 adds support for pyinstaller (v4)\n  (Thank you, Bob Thomas!)\n- 2020-05-19 adds compatibility with Windows 7\n  (Thank you, demberto!)\n- 2020-07-22 fixes freezing bug on Linux during startup\n  (Thank you, zhujisheng!)\n- 2020-08-01 improves error reporting on Linux\n  (Thank you, Rik van Riel!)\n- 2020-08-13 fixes crash due to use-after-free on Linux\n  (Thank you, Rik van Riel!)\n- 2021-01-13 fixes unicode error on Windows\n  (Thank you, paulzzh!)\n- 2021-11-24 adds compatibility with NixOS library naming\n  (Thank you, shithead!)\n- 2021-12-23 fixes deprecation for Python 3.10\n  (Thank you, Nekyo!)\n- 2022-04-29 fixes deprecation in recent Numpy\n- 2024-03-16 fixes empty soundcard list on macOS\n  (Thank you, Patrice Brend'amour!)\n",
    "bugtrack_url": null,
    "license": "BSD 3-clause",
    "summary": "Play and record audio without resorting to CPython extensions",
    "version": "0.4.3",
    "project_urls": {
        "Homepage": "https://github.com/bastibe/SoundCard"
    },
    "split_keywords": [],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "e91d13d4c96e3785f00e7b0ae2fd04fd1c7a6016345114594a1050c8471a907a",
                "md5": "1338c701d1672b1565308e058ff344b7",
                "sha256": "2af6f6b49c24dc8a997d8189206206f1bf1d48d7e8f313777293996809cfdfe3"
            },
            "downloads": -1,
            "filename": "SoundCard-0.4.3-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "1338c701d1672b1565308e058ff344b7",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.5",
            "size": 43684,
            "upload_time": "2024-03-19T16:23:15",
            "upload_time_iso_8601": "2024-03-19T16:23:15.892011Z",
            "url": "https://files.pythonhosted.org/packages/e9/1d/13d4c96e3785f00e7b0ae2fd04fd1c7a6016345114594a1050c8471a907a/SoundCard-0.4.3-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "fe618fa850aacd49ad4c838cb51cd8893c1696ac32693efc22640f39f8190d50",
                "md5": "53d057d8a305d5db2998a65d9b23aeaa",
                "sha256": "410835514ba10809803cb9887d4270f392b59eaf365915bb94516af3f8b1d037"
            },
            "downloads": -1,
            "filename": "SoundCard-0.4.3.tar.gz",
            "has_sig": false,
            "md5_digest": "53d057d8a305d5db2998a65d9b23aeaa",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.5",
            "size": 40609,
            "upload_time": "2024-03-19T16:23:18",
            "upload_time_iso_8601": "2024-03-19T16:23:18.642383Z",
            "url": "https://files.pythonhosted.org/packages/fe/61/8fa850aacd49ad4c838cb51cd8893c1696ac32693efc22640f39f8190d50/SoundCard-0.4.3.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-03-19 16:23:18",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "bastibe",
    "github_project": "SoundCard",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": false,
    "lcname": "soundcard"
}
        
Elapsed time: 0.45804s