Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Add python-sounddevice and set it the default audio library #69

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -85,11 +85,15 @@ For validation, run::
optional arguments:
-h, --help show this help message and exit

`python-sounddevice <https://python-sounddevice.readthedocs.io>` is used by default as the audio library.
This should work out-of-the box on Linux, Windows and macOS, however, other choices are available.

On, Windows you may download the `portaudio` library from `MinGW <https://packages.msys2.org/base/mingw-w64-portaudio>`_.
Then, you should specify the DLL using the following command-line flag::

-l AUDIO_LIBRARY, --audio-library AUDIO_LIBRARY
File name of PortAudio shared library.

The AUDIO_LIBRARY can be 'alsa', 'sd' (the default) or the file name for the PortAudio shared library.


Calibration
Expand Down
10 changes: 7 additions & 3 deletions amodem/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,8 +169,9 @@ def create_parser(description, interface_factory):
for sub in subparsers.choices.values():
sub.add_argument('-c', '--calibrate', nargs='?', default=False,
metavar='SYSTEM', help=calibration_help)
sub.add_argument('-l', '--audio-library', default='libportaudio.so',
help='File name of PortAudio shared library.')
sub.add_argument('-l', '--audio-library', default='sd',
help="'alsa', 'sd' or file name of "
"PortAudio shared library")
sub.add_argument('-z', '--zlib', default=False, action='store_true',
help='Use zlib to compress/decompress data.')
g = sub.add_mutually_exclusive_group()
Expand Down Expand Up @@ -234,9 +235,12 @@ def interface_factory():
import pylab # pylint: disable=import-error,import-outside-toplevel
args.pylab = pylab

if args.audio_library == 'ALSA':
if args.audio_library in ['alsa', 'ALSA']:
from . import alsa # pylint: disable=import-outside-toplevel
interface = alsa.Interface(config)
elif args.audio_library == 'sd':
from . import sd # pylint: disable=import-outside-toplevel
interface = sd.Interface(config)
elif args.audio_library == '-':
interface = _Dummy() # manually disable PortAudio
elif args.command == 'send' and args.output is not None:
Expand Down
69 changes: 69 additions & 0 deletions amodem/sd.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
"""
Code which adds sounddevice lib support for interfaces, recording and playing.
"""

import logging
import sounddevice as sd

log = logging.getLogger(__name__)


class Interface:

def __init__(self, config):
self.config = config
bits_per_sample = config.bits_per_sample
assert bits_per_sample == 16

def __enter__(self):
return self

def __exit__(self, *args):
pass

def recorder(self):
return Recorder(self)

def player(self):
return Player(self)


class Recorder:
def __init__(self, lib):
self.bufsize = 4096

self.audio_stream = sd.RawInputStream(
samplerate=lib.config.Fs,
blocksize=self.bufsize,
channels=1, dtype='int16')
self.audio_stream.start()

def read(self, size):
data, overflowed = self.audio_stream.read(size)
if overflowed:
raise OverflowError("Overflow reading from audio device")
return data

def close(self):
self.audio_stream.stop()
self.audio_stream.close()


class Player:
def __init__(self, lib):
self.buffer_length_ms = 10
self.buffer_size = int(lib.config.Fs * (self.buffer_length_ms / 1000))

self.audio_stream = sd.RawOutputStream(
samplerate=lib.config.Fs,
blocksize=self.buffer_size,
channels=1, dtype='int16')

self.audio_stream.start()

def write(self, data):
self.audio_stream.write(data)

def close(self):
self.audio_stream.stop()
self.audio_stream.close()
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ def run_tests(self):
packages=['amodem'],
tests_require=['pytest'],
cmdclass={'test': PyTest},
install_requires=['numpy'],
install_requires=['numpy','sounddevice'],
platforms=['POSIX'],
classifiers=[
'Development Status :: 5 - Production/Stable',
Expand Down