Coverage for src/audioio/audiomodules.py: 75%
428 statements
« prev ^ index » next coverage.py v7.16.2, created at 2026-10-19 19:14 +0000
« prev ^ index » next coverage.py v7.16.2, created at 2026-10-19 19:14 +0000
1"""Query and control installation status and availability of audio modules.
3`list_modules()` and `installed_modules()` let you query which audio
4modules are currently installed on your system.
6Call `missing_modules()` for a list of module names that should be
7installed. The `missing_modules_instructions()` function prints
8installation instructions for packages you should install for better
9performance. For installation instructions on a specific module use
10`installation_instruction()`.
12By default all installed modules are used by the audioio functions.
13The `disable_module()`, `enable_module()` and `select_module()`
14functions allow to control which of the installed audio modules
15should be used by the audioio functions.
17`list_modules()`, `available_modules()` and `unavailable_modules()` let
18you query which audio modules are installed and available and which
19modules are not available on your system.
22## Functions
24- `installed_modules()`: installed audio modules.
25- `available_modules()`: installed and enabled audio modules.
26- `unavailable_modules()`: audio modules that are not installed and not enabled.
27- `disable_module()`: disable audio module.
28- `enable_module()`: enable audio modules provided they are installed.
29- `select_module()`: select (enable) a single audio module and disable all others.
30- `list_modules()`: print list of all supported modules and their installation status.
31- `missing_modules()`: missing audio modules that are recommended to be installed.
32- `missing_modules_instructions()`: print installation instructions for missing but useful audio modules.
33- `installation_instruction()`: instructions on how to install a specific audio module.
34- `main()`: command line program for listing installation status of audio modules.
37## Command line script
39Run this module as a script from within the audioio source tree
40```sh
41> python -m src.audioio.auidomodules
42```
43or, once the audioio package is installed on your system, simply run
44```sh
45> audiomodules
46```
47for an overview of audio packages, their installation status, and recommendations on
48how to install further audio packages. The output looks like this:
50```text
51Status of audio packages on this machine:
52-----------------------------------------
54wave is installed (F)
55ewave is installed (F)
56scipy.io.wavfile is installed (F)
57soundfile is installed (F)
58wavefile is installed (F)
59wavpack is installed (F)
60audioread is installed (F)
61pyaudio is installed (D)
62sounddevice not installed (D)
63simpleaudio is installed (D)
64soundcard is installed (D)
65ossaudiodev is installed (D)
66winsound not installed (D)
68F: file I/O, D: audio device
70There is no need to install additional audio packages.
71```
73For instructions on specific packages, run `audiomodules` with the name of
74the package supplied as argument:
76```sh
77> audiomodules soundfile
78```
79This produces something like this:
80```text
81...
82Installation instructions for the soundfile module:
83---------------------------------------------------
84The soundfile package is a wrapper of the sndfile library,
85that supports many different audio file formats.
86See http://python-soundfile.readthedocs.org for a documentation of the soundfile python wrapper
87and http://www.mega-nerd.com/libsndfile for details on the sndfile library.
89First, install the following packages:
91sudo apt install libsndfile1 libsndfile1-dev libffi-dev
93Install the soundfile module with pip:
95sudo pip install SoundFile
97or alternatively from your distribution's package:
99sudo apt install python3-soundfile
100```
102Running
103```sh
104audiomodules --help
105```
106prints
107```text
108usage: audiomodules [--version] [--help] [PACKAGE]
110Installation status and instructions of python audio packages.
112optional arguments:
113 --help show this help message and exit
114 --version show version number and exit
115 PACKAGE show installation instructions for PACKAGE
117version 2.2.0 by Benda-Lab (2015-2024)
118```
120## Links
122For an overview on python modules regarding file I/O see, for example,
123http://nbviewer.jupyter.org/github/mgeier/python-audio/blob/master/audio-files/index.ipynb
125For an overview on packages for playing and recording audio, see
126https://realpython.com/playing-and-recording-sound-python/
128"""
130import sys
131import os
133from .version import __version__, __year__
136audio_modules = {}
137""" Dictionary with availability of various audio modules.
138Keys are the module names, values are booleans.
139Based on this dictionary audioio employs functions of installed audio modules. """
141audio_installed = []
142""" List of installed audio modules. """
144audio_infos = {}
145""" Dictionary with information about all supported audio modules.
146Keys are the module names, values are the informations. """
148audio_instructions_linux = {}
149""" Dictionary with general installation instructions for linux that
150are needed in addition to installing some packages.
151Keys are the module names, values are the instructions. """
153audio_instructions_windows = {}
154""" Dictionary with general installation instructions for windows that
155are needed in addition to installing some packages.
156Keys are the module names, values are the instructions. """
158audio_pip_packages = {}
159""" Dictionary with pip package names of the audio modules.
160Keys are the module names, values are pip package names. """
162audio_conda_packages = {}
163""" Dictionary with conda package names of the audio modules.
164Keys are the module names, values are conda package names,
165optionally with a channel specification. """
167audio_deb_packages = {}
168""" Dictionary with Linux DEB packages of the audio modules.
169Keys are the module names, values are the package names. """
171audio_rpm_packages = {}
172""" Dictionary with Linux RPM packages of the audio modules.
173Keys are the module names, values are the package names. """
175audio_brew_packages = {}
176""" Dictionary with macOS homebrew packages of the audio modules.
177Keys are the module names, values are the package (formulae) names. """
179audio_required_deb_packages = {}
180""" Dictionary with Linux DEB packages required for the audio modules.
181Keys are the module names, values are lists of string with package names. """
183audio_required_rpm_packages = {}
184""" Dictionary with Linux RPM packages required for the audio modules.
185Keys are the module names, values are lists of string with package names. """
187audio_required_brew_packages = {}
188""" Dictionary with macOS homebrew packages required for the audio modules.
189Keys are the module names, values are lists of string with package (formulae) names. """
191audio_fileio = []
192""" List of audio modules used for reading and writing audio files. """
194audio_device = []
195""" List of audio modules used for playing and recording sounds on audio devices. """
198# probe for available audio modules:
200audio_fileio.append('wave')
201try:
202 import wave
203 audio_modules['wave'] = True
204 audio_installed.append('wave')
205except ImportError:
206 audio_modules['wave'] = False
207audio_infos['wave'] = """The wave module is part of the standard python library.
208For documentation see https://docs.python.org/3.8/library/wave.html"""
210audio_fileio.append('ewave')
211try:
212 import ewave
213 audio_modules['ewave'] = True
214 audio_installed.append('ewave')
215except ImportError:
216 audio_modules['ewave'] = False
217audio_pip_packages['ewave'] = 'ewave'
218audio_conda_packages['ewave'] = '-c auto ewave'
219audio_infos['ewave'] = """The ewave package supports more types of WAV-files than the standard wave module.
220For documentation see https://github.com/melizalab/py-ewave"""
222audio_fileio.append('scipy.io.wavfile')
223try:
224 from scipy.io import wavfile
225 audio_modules['scipy.io.wavfile'] = True
226 audio_installed.append('scipy.io.wavfile')
227except ImportError:
228 audio_modules['scipy.io.wavfile'] = False
229audio_pip_packages['scipy.io.wavfile'] = 'scipy'
230audio_conda_packages['scipy.io.wavfile'] = 'scipy'
231audio_deb_packages['scipy.io.wavfile'] = 'python3-scipy'
232audio_rpm_packages['scipy.io.wavfile'] = 'python3-scipy'
233audio_brew_packages['scipy.io.wavfile'] = 'scipy'
234audio_infos['scipy.io.wavfile'] = """The scipy package provides very basic functions for reading WAV files.
235For documentation see http://docs.scipy.org/doc/scipy/reference/io.html"""
237audio_fileio.append('soundfile')
238try:
239 import soundfile
240 audio_modules['soundfile'] = True
241 audio_installed.append('soundfile')
242except ImportError:
243 audio_modules['soundfile'] = False
244audio_pip_packages['soundfile'] = 'SoundFile'
245audio_conda_packages['soundfile'] = '-c conda-forge soundfile'
246audio_deb_packages['soundfile'] = 'python3-soundfile'
247audio_required_deb_packages['soundfile'] = ['libsndfile1', 'libsndfile1-dev', 'libffi-dev']
248audio_required_rpm_packages['soundfile'] = ['libsndfile', 'libsndfile-devel', 'libffi-devel']
249audio_infos['soundfile'] = """The soundfile package is a wrapper of the sndfile library,
250that supports many different audio file formats.
251See http://python-soundfile.readthedocs.org for a documentation of the soundfile python wrapper
252and http://www.mega-nerd.com/libsndfile for details on the sndfile library."""
254audio_fileio.append('wavefile')
255try:
256 import wavefile
257 audio_modules['wavefile'] = True
258 audio_installed.append('wavefile')
259except ImportError:
260 audio_modules['wavefile'] = False
261audio_pip_packages['wavefile'] = 'wavefile'
262audio_required_deb_packages['wavefile'] = ['libsndfile1', 'libsndfile1-dev', 'libffi-dev']
263audio_required_rpm_packages['wavefile'] = ['libsndfile', 'libsndfile-devel', 'libffi-devel']
264audio_required_brew_packages['wavefile'] = ['libsndfile', 'libffi']
265audio_infos['wavefile'] = """The wavefile package is a wrapper of the sndfile library,
266that supports many different audio file formats.
267See https://github.com/vokimon/python-wavefile for documentation of the wavefile python wrapper
268and http://www.mega-nerd.com/libsndfile for details on the sndfile library."""
270audio_fileio.append('wavpack')
271try:
272 import ctypes
273 if sys.platform.startswith('win'):
274 lib_name = 'wavpack.dll'
275 elif sys.platform.startswith('darwin'):
276 lib_name = 'libwavpack.dylib'
277 else:
278 lib_name = 'libwavpack.so.1'
279 wavpack = ctypes.CDLL(lib_name)
280 wavpack.WavpackOpenFileInput.restype = ctypes.c_void_p
281 wavpack.WavpackGetNumSamples64.restype = ctypes.c_int64
282 wavpack.WavpackGetWrapperData.restype = ctypes.POINTER(ctypes.c_ubyte)
283 wavpack.WavpackSeekSample64.argtypes = [ctypes.c_void_p, ctypes.c_int64]
284 wavpack.WavpackUnpackSamples.argtypes = [ctypes.c_void_p,
285 ctypes.POINTER(ctypes.c_int32),
286 ctypes.c_uint32]
287 wavpack.WavpackBlockOutput = ctypes.CFUNCTYPE(
288 ctypes.c_int, # return type
289 ctypes.py_object, # id (holds file descriptor reference)
290 ctypes.POINTER(ctypes.c_ubyte), # data (pointer to the block buffer)
291 ctypes.c_int32 # bcount (number of bytes to write)
292 )
293 class WavpackConfig(ctypes.Structure):
294 _fields_ = [('bitrate', ctypes.c_float),
295 ('shaping_weight', ctypes.c_float),
296 ('bits_per_sample', ctypes.c_int),
297 ('bytes_per_sample', ctypes.c_int),
298 ('qmode', ctypes.c_int),
299 ('flags', ctypes.c_int),
300 ('xmode', ctypes.c_int),
301 ('num_channels', ctypes.c_int),
302 ('float_norm_exp', ctypes.c_int),
303 ('block_samples', ctypes.c_int32),
304 ('worker_threads', ctypes.c_int32),
305 ('sample_rate', ctypes.c_int32),
306 ('channel_mask', ctypes.c_int32),
307 ('md5_checksum', ctypes.c_ubyte*16),
308 ('md5_read', ctypes.c_ubyte),
309 ('num_tag_strings', ctypes.c_int),
310 ('tag_strings', ctypes.POINTER(ctypes.c_char_p))]
311 wavpack.CONFIG_FLOAT_DATA = 0x80 # internal flag from wavpack_local.h: IEEE 32-bit float data
312 wavpack.WavpackOpenFileOutput.restype = ctypes.c_void_p
313 wavpack.WavpackOpenFileOutput.argtypes = [wavpack.WavpackBlockOutput,
314 ctypes.py_object,
315 ctypes.py_object]
316 wavpack.WavpackAddWrapper.restype = ctypes.c_int
317 wavpack.WavpackAddWrapper.argtypes = [ctypes.c_void_p,
318 ctypes.c_char_p,
319 ctypes.c_uint]
320 wavpack.WavpackSetConfiguration64.restype = ctypes.c_int
321 wavpack.WavpackSetConfiguration64.argtypes = [ctypes.c_void_p,
322 ctypes.POINTER(WavpackConfig),
323 ctypes.c_int64,
324 ctypes.c_char_p]
325 wavpack.WavpackPackInit.restype = ctypes.c_int
326 wavpack.WavpackPackInit.argtypes = [ctypes.c_void_p]
327 wavpack.WavpackPackSamples.restype = ctypes.c_int
328 wavpack.WavpackPackSamples.argtypes = [ctypes.c_void_p,
329 ctypes.POINTER(ctypes.c_int32),
330 ctypes.c_uint32]
331 wavpack.WavpackFlushSamples.restype = ctypes.c_int
332 wavpack.WavpackFlushSamples.argtypes = [ctypes.c_void_p]
333 wavpack.WavpackCloseFile.restype = ctypes.c_void_p
334 wavpack.WavpackCloseFile.argtypes = [ctypes.c_void_p]
335 audio_modules['wavpack'] = True
336 audio_installed.append('wavpack')
337except (OSError, AttributeError): # no library or too old
338 audio_modules['wavpack'] = False
339audio_deb_packages['wavpack'] = 'libwavpack1'
340audio_rpm_packages['wavpack'] = 'wavpack-libs'
341audio_brew_packages['wavpack'] = 'wavpack'
342audio_infos['wavpack'] = """The wavpack library reads and writes WavPack files, a lossless compression of audio data.
343It is called via ctypes, no python package is needed.
344For documentation see https://www.wavpack.com"""
346audio_fileio.append('audioread')
347try:
348 import audioread
349 audio_modules['audioread'] = True
350 audio_installed.append('audioread')
351except ImportError:
352 audio_modules['audioread'] = False
353audio_pip_packages['audioread'] = 'audioread'
354audio_conda_packages['audioread'] = '-c conda-forge audioread'
355audio_deb_packages['audioread'] = 'python3-audioread'
356audio_rpm_packages['audioread'] = 'python3-audioread'
357audio_required_deb_packages['audioread'] = ['ffmpeg', 'libavcodec-extra']
358audio_required_rpm_packages['audioread'] = ['ffmpeg', 'ffmpeg-devel', 'libavcodec-extra']
359audio_required_brew_packages['audioread'] = ['libav --with-libvorbis --with-sdl --with-theora', 'ffmpeg --with-libvorbis --with-sdl2 --with-theora']
360audio_infos['audioread'] = """The audioread package uses libav (https://libav.org/) or ffmpeg (https://ffmpeg.org/) to make mpeg files readable.
361Install this package for reading mpeg files.
362For documentation see https://github.com/beetbox/audioread"""
364audio_fileio.append('pydub')
365try:
366 import pydub
367 audio_modules['pydub'] = True
368 audio_installed.append('pydub')
369except ImportError:
370 audio_modules['pydub'] = False
371audio_pip_packages['pydub'] = 'pydub'
372audio_conda_packages['pydub'] = '-c conda-forge pydub'
373audio_deb_packages['pydub'] = 'python3-pydub'
374audio_rpm_packages['pydub'] = 'python3-pydub'
375audio_required_deb_packages['pydub'] = ['ffmpeg', 'libavcodec-extra']
376audio_required_rpm_packages['pydub'] = ['ffmpeg', 'ffmpeg-devel', 'libavcodec-extra']
377audio_required_brew_packages['pydub'] = ['libav --with-libvorbis --with-sdl --with-theora', 'ffmpeg --with-libvorbis --with-sdl2 --with-theora']
378audio_infos['pydub'] = """The pydub package uses libav (https://libav.org/) or ffmpeg (https://ffmpeg.org/) to make mpeg files readable and writeable.
379Install this package if you need to write mpeg files.
380For documentation see https://github.com/jiaaro/pydub"""
382audio_device.append('pyaudio')
383try:
384 import pyaudio
385 audio_modules['pyaudio'] = True
386 audio_installed.append('pyaudio')
387except ImportError:
388 audio_modules['pyaudio'] = False
389audio_pip_packages['pyaudio'] = 'PyAudio'
390audio_conda_packages['pyaudio'] = 'pyaudio'
391audio_deb_packages['pyaudio'] = 'python3-pyaudio # WARNING: broken on Ubuntu with python 3.10, use pip instead'
392audio_rpm_packages['pyaudio'] = 'python3-pyaudio'
393audio_required_deb_packages['pyaudio'] = ['libportaudio2']
394audio_required_rpm_packages['pyaudio'] = ['libportaudio', 'portaudio-devel']
395audio_required_brew_packages['pyaudio'] = ['portaudio']
396audio_infos['pyaudio'] = """The pyaudio package is a wrapper of the portaudio library (http://www.portaudio.com).
397This is an alternative to the sounddevice package with similar properties.
398For documentation see https://people.csail.mit.edu/hubert/pyaudio."""
399audio_instructions_windows['pyaudio'] = """Download an appropriate (latest version, 32 or 64 bit) wheel from
400<https://www.lfd.uci.edu/~gohlke/pythonlibs/#pyaudio>. Install this file with pip,
401that is go to the folder where the wheel file is downloaded and run
403pip install PyAudio-0.2.11-cp39-cp39-win_amd64.whl
405replace the wheel file name by the one you downloaded."""
407audio_device.append('sounddevice')
408try:
409 import sounddevice
410 audio_modules['sounddevice'] = True
411 audio_installed.append('sounddevice')
412except ImportError:
413 audio_modules['sounddevice'] = False
414audio_pip_packages['sounddevice'] = 'sounddevice'
415audio_conda_packages['sounddevice'] = '-c conda-forge python-sounddevice'
416audio_required_deb_packages['sounddevice'] = ['libportaudio2', 'python3-cffi']
417audio_required_rpm_packages['sounddevice'] = ['libportaudio', 'portaudio-devel', 'python3-cffi']
418audio_required_brew_packages['sounddevice'] = ['portaudio']
419audio_infos['sounddevice'] = """The sounddevice package is a wrapper of the portaudio library (http://www.portaudio.com).
420For documentation see https://python-sounddevice.readthedocs.io"""
422audio_device.append('simpleaudio')
423try:
424 import simpleaudio
425 audio_modules['simpleaudio'] = True
426 audio_installed.append('simpleaudio')
427except ImportError:
428 audio_modules['simpleaudio'] = False
429audio_pip_packages['simpleaudio'] = 'simpleaudio'
430audio_rpm_packages['simpleaudio'] = 'python3-simpleaudio'
431audio_required_deb_packages['simpleaudio'] = ['python3-dev', 'libasound2-dev']
432audio_required_rpm_packages['simpleaudio'] = ['python3-devel', 'alsa-lib', 'alsa-lib-devel']
433audio_infos['simpleaudio'] = """The simpleaudio package is a lightweight package
434for cross-platform audio playback.
435Unfortunately, this package is no longer maintained.
436For documentation see https://simpleaudio.readthedocs.io"""
438audio_device.append('soundcard')
439try:
440 import soundcard
441 audio_modules['soundcard'] = True
442 audio_installed.append('soundcard')
443except ImportError:
444 audio_modules['soundcard'] = False
445except AssertionError:
446 audio_modules['soundcard'] = False
447audio_pip_packages['soundcard'] = 'soundcard'
448audio_infos['soundcard'] = """SoundCard is a library for playing and recording audio without
449resorting to a CPython extension. Instead, it is implemented using the
450wonderful CFFI and the native audio libraries of Linux, Windows and
451macOS.
452For documentation see https://github.com/bastibe/SoundCard"""
454audio_device.append('ossaudiodev')
455try:
456 import ossaudiodev
457 audio_modules['ossaudiodev'] = True
458 audio_installed.append('ossaudiodev')
459except ImportError:
460 audio_modules['ossaudiodev'] = False
461audio_required_deb_packages['ossaudiodev'] = ['osspd']
462audio_infos['ossaudiodev'] = """The ossaudiodev module is part of the python standard library and
463provides simple support for sound playback under Linux based on the (outdated) OSS system.
464You most likely want to install the simpleaudio or the soundfile package for better performance.
465For documentation see https://docs.python.org/3.8/library/ossaudiodev.html"""
467audio_device.append('winsound')
468try:
469 import winsound
470 audio_modules['winsound'] = True
471 audio_installed.append('winsound')
472except ImportError:
473 audio_modules['winsound'] = False
474audio_infos['winsound'] = """The winsound module is part of the python standard library and
475provides simple support for sound playback under Windows. If possible,
476install the simpleaudio package in addition for better performance.
477For documentation see https://docs.python.org/3.6/library/winsound.html and
478https://mail.python.org/pipermail/tutor/2012-September/091529.html"""
481def installed_modules(func='all'):
482 """Installed audio modules.
484 By default all installed modules are available. With
485 `disable_module()`, `enable_module()` and `select_module()`
486 the availability of installed modules can be controlled.
488 Parameters
489 ----------
490 func: string
491 'all': all installed audio modules.
492 'fileio': installed audio modules used for file I/O.
493 'device': installed audio modules used for playing and recording sounds.
495 Returns
496 -------
497 mods: list of strings
498 List of installed audio modules of the requested function.
500 See Also
501 --------
502 available_modules()
503 """
504 if func == 'fileio':
505 return [module for module in audio_fileio if module in audio_installed]
506 elif func == 'device':
507 return [module for module in audio_device if module in audio_installed]
508 else:
509 return audio_installed
512def available_modules(func='all'):
513 """Installed and enabled audio modules.
515 By default all installed modules are available. With
516 `disable_module()`, `enable_module()` and `select_module()`
517 the availability of installed modules can be controlled.
519 Parameters
520 ----------
521 func: string
522 'all': all installed audio modules.
523 'fileio': installed audio modules used for file I/O.
524 'device': installed audio modules used for playing and recording sounds.
526 Returns
527 -------
528 mods: list of strings
529 List of available, i.e. installed and enabled, audio modules
530 of the requested function.
531 """
532 if func == 'fileio':
533 return [module for module in audio_fileio if audio_modules[module]]
534 elif func == 'device':
535 return [module for module in audio_device if audio_modules[module]]
536 else:
537 return [module for module in audio_installed if audio_modules[module]]
540def unavailable_modules(func='all'):
541 """Audio modules that are not installed and not enabled.
543 Parameters
544 ----------
545 func: string
546 'all': all installed audio modules.
547 'fileio': installed audio modules used for file I/O.
548 'device': installed audio modules used for playing and recording sounds.
550 Returns
551 -------
552 mods: list of strings
553 List of not available, i.e. not installed and not enabled, audio modules
554 of the requested function.
555 """
556 if func == 'fileio':
557 return [module for module in audio_fileio if not audio_modules[module]]
558 elif func == 'device':
559 return [module for module in audio_device if not audio_modules[module]]
560 else:
561 return [module for module in audio_modules.keys() if not audio_modules[module]]
564def disable_module(module=None):
565 """Disable an audio module.
567 A disabled module is not used by the audioio functions and classes.
568 To disable all modules except one, call `select_module()`.
570 Parameters
571 ----------
572 module: string or None
573 Name of the module to be disabled as it appears in `available_modules()`.
574 If None disable all installed audio modules.
576 See Also
577 --------
578 enable_module(), select_module(), available_modules(), list_modules()
579 """
580 if module is None:
581 for module in audio_installed:
582 audio_modules[module] = False
583 elif module in audio_modules:
584 audio_modules[module] = False
587def enable_module(module=None):
588 """Enable audio modules provided they are installed.
590 Parameters
591 ----------
592 module: string or None
593 Name of the module to be (re)enabled.
594 If None enable all installed audio modules.
596 See Also
597 --------
598 disable_module(), available_modules(), list_modules()
599 """
600 if module is None:
601 for module in audio_installed:
602 audio_modules[module] = True
603 elif module in audio_modules:
604 audio_modules[module] = (module in audio_installed)
607def select_module(module):
608 """Select (enable) a single audio module and disable all others.
610 Undo by calling `enable_module()` without arguments.
612 Parameters
613 ----------
614 module: string
615 Name of the module to be selected.
617 Returns
618 -------
619 selected: bool
620 False if the module can not be selected, because it is not installed.
621 In this case the other modules are not disabled.
623 See Also
624 --------
625 enable_module(), disable_module(), available_modules(), list_modules()
626 """
627 if module not in audio_installed:
628 return False
629 for mod in audio_installed:
630 audio_modules[mod] = (mod == module)
631 return True
634def list_modules(module='all', availability=True):
635 """Print list of all supported modules and their installation status.
637 Modules that are not installed but are recommended are marked
638 with an all uppercase "NOT installed".
640 Parameters
641 ----------
642 module: string
643 If 'all' list all modules.
644 If 'fileio' list all modules used for file I/O.
645 If 'device' list all modules used for playing and recording sounds.
646 Otherwise list only the specified module.
647 availability: bool
648 Mark availability of each module by an asterisk.
650 See Also
651 --------
652 installed_modules()
653 missing_modules()
654 missing_modules_instructions()
655 """
656 def print_module(module, missing, print_type):
657 audio_avail = ''
658 if availability:
659 audio_avail = '* ' if audio_modules[module] else ' '
660 audio_type = ''
661 if print_type:
662 if module in audio_fileio:
663 audio_type += 'F'
664 if module in audio_device:
665 audio_type += 'D'
666 if len(audio_type) > 0:
667 audio_type = f' ({audio_type})'
668 if module in audio_installed:
669 print(f'{audio_avail}{module:<17s} is installed{audio_type}')
670 elif module in missing:
671 print(f'{audio_avail}{module:<17s} NOT installed{audio_type}')
672 else:
673 print(f'{audio_avail}{module:<17s} not installed{audio_type}')
675 missing = missing_modules()
676 if module not in ['all', 'fileio', 'device']:
677 print_module(module, missing, True)
678 else:
679 print_type = (module == 'all')
680 modules = sorted(audio_modules.keys())
681 if module in ['all', 'fileio']:
682 for mod in audio_fileio:
683 print_module(mod, missing, print_type)
684 modules.remove(mod)
685 if module in ['all', 'device']:
686 for mod in audio_device:
687 if mod in modules:
688 print_module(mod, missing, print_type)
689 modules.remove(mod)
690 if module == 'all':
691 for mod in modules:
692 print_module(mod, missing, print_type)
695def missing_modules(func='all'):
696 """Missing audio modules that are recommended to be installed.
698 Parameters
699 ----------
700 func: string
701 'all': missing audio modules of all functions.
702 'fileio': missing audio modules for file I/O.
703 'device': missing audio modules for playing and recording sounds.
705 Returns
706 -------
707 mods: list of strings
708 List of missing audio modules of the requested function.
709 """
710 mods = []
711 if func in ['all', 'fileio']:
712 if 'soundfile' not in audio_installed and \
713 'wavefile' not in audio_installed:
714 mods.append('soundfile')
715 if 'audioread' not in audio_installed:
716 mods.append('audioread')
717 if 'pydub' not in audio_installed:
718 mods.append('pydub')
719 if func in ['all', 'device']:
720 if 'pyaudio' not in audio_installed and \
721 'sounddevice' not in audio_installed:
722 mods.append('sounddevice')
723 return mods
726def missing_modules_instructions(func='all'):
727 """Print installation instructions for missing but useful audio modules.
729 Parameters
730 ----------
731 func: string
732 'all': missing audio modules of all functions.
733 'fileio': missing audio modules for file I/O.
734 'device': missing audio modules for playing and recording sounds.
735 """
736 mods = missing_modules(func)
737 if len(mods) > 0 :
738 print('For better performance you should install the following modules:')
739 for mod in mods:
740 print()
741 print(f'{mod}:')
742 print('-'*(len(mod)+1))
743 print(installation_instruction(mod))
744 else:
745 print('There is no need to install additional audio packages.')
748def installation_instruction(module):
749 """Instructions on how to install a specific audio module.
751 Parameters
752 ----------
753 module: string
754 The name of the module for which an instruction should be printed.
756 Returns
757 -------
758 msg: multi-line string
759 Installation instruction for the requested module.
760 """
761 install_package_deb = "sudo apt install"
762 install_package_rpm = "dnf install"
763 install_package_brew = "brew install"
764 install_package = None
765 package = None
766 required_packages = None
767 multiline = False
768 instruction = None
770 install_pip_deb = "sudo pip install"
771 install_pip_rpm = "pip install"
772 install_pip_osx = "pip install"
773 install_pip_win = "pip install"
774 install_pip = install_pip_deb
776 install_conda = "conda install"
778 # check operating system:
779 if sys.platform[0:5] == "linux":
780 if os.path.exists('/etc/redhat-release') or os.path.exists('/etc/fedora-release'):
781 install_package = install_package_rpm
782 install_pip = install_pip_rpm
783 package = audio_rpm_packages.get(module, None)
784 required_packages = audio_required_rpm_packages.get(module, None)
785 else:
786 install_package = install_package_deb
787 package = audio_deb_packages.get(module, None)
788 required_packages = audio_required_deb_packages.get(module, None)
789 instruction = audio_instructions_linux.get(module, None)
790 elif sys.platform == "darwin":
791 install_package = install_package_brew
792 install_pip = install_pip_osx
793 package = audio_brew_packages.get(module, None)
794 required_packages = audio_required_brew_packages.get(module, None)
795 multiline = True
796 elif sys.platform[0:3] == "win":
797 install_package = ''
798 install_pip = install_pip_win
799 instruction = audio_instructions_windows.get(module, None)
800 # check conda:
801 conda = "CONDA_DEFAULT_ENV" in os.environ
802 conda_package = audio_conda_packages.get(module, None)
803 if conda:
804 install_pip = install_pip.replace('sudo ', '')
806 pip_package = audio_pip_packages.get(module, None)
808 req_inst = None
809 if required_packages is not None:
810 if multiline:
811 ps = '\n'.join([install_package + ' ' + p for p in required_packages])
812 else:
813 ps = install_package + ' ' + ' '.join(required_packages)
814 if pip_package is None and package is None:
815 req_inst = 'Install the following packages:\n\n' + ps
816 else:
817 req_inst = 'First, install the following packages:\n\n' + ps
819 pip_inst = None
820 if pip_package is not None:
821 pip_inst = f'Install the {module} module with pip:\n\n{install_pip} {pip_package}'
823 dist_inst = None
824 if package is not None:
825 if pip_inst is None:
826 dist_inst = f'Install module from your distribution\'s package:\n\n{install_package} {package}'
827 else:
828 dist_inst = f'or alternatively from your distribution\'s package:\n\n{install_package} {package}'
830 conda_inst = None
831 if conda and conda_package is not None:
832 conda_inst = f'Install the {module} module with conda:\n\n{install_package} {package}'
833 req_inst = pip_inst = dist_inst = instruction = None
835 info = audio_infos.get(module, None)
837 msg = ''
838 for s in [info, conda_inst, req_inst, pip_inst, dist_inst, instruction]:
839 if s is not None:
840 if len(msg) > 0:
841 msg += '\n\n'
842 msg += s
844 return msg
847def main(*args):
848 """ Command line program for listing installation status of audio modules.
850 Run this module as a script
851 ```
852 > python -m src.audioio.auidomodules
853 ```
854 or, when the audioio package is installed on your system, simply run
855 ```sh
856 > audiomodules
857 ```
858 for an overview of audio packages, their installation status, and recommendations on
859 how to install further audio packages.
861 The '--help' argument prints out a help message:
862 ```sh
863 > audiomodules --help
864 ```
866 Parameters
867 ----------
868 args: list of strings
869 Command line arguments as provided by sys.argv[1:]
870 """
871 if len(args) == 0:
872 args = sys.argv[1:]
873 if len(args) > 0:
874 if args[0] == '--version':
875 print(f'version {__version__} by Benda-Lab (2015-{__year__})')
876 sys.exit(0)
877 if args[0] == '--help' or args[0] == '-h':
878 print('usage: audiomodules [--version] [--help] [PACKAGE]')
879 print('')
880 print('Installation status and instructions of python audio packages.')
881 print('')
882 print('optional arguments:')
883 print(' --help show this help message and exit')
884 print(' --version show version number and exit')
885 print(' PACKAGE show installation instructions for PACKAGE')
886 print('')
887 print(f'version {__version__} by Benda-Lab (2015-{__year__})')
888 return
890 print('')
891 if len(args) > 0 :
892 mod = args[0]
893 if mod in audio_modules:
894 print(f'Installation instructions for the {mod} module:')
895 print('-'*(42+len(mod)))
896 print(installation_instruction(mod))
897 print('')
898 else:
899 print('Status of audio packages on this machine:')
900 print('-'*41)
901 print('')
902 list_modules('all', False)
903 print('')
904 print('F: file I/O, D: audio device')
905 print('')
906 missing_modules_instructions()
907 print('')
910if __name__ == "__main__":
911 main(*sys.argv[1:])