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

1"""Query and control installation status and availability of audio modules. 

2 

3`list_modules()` and `installed_modules()` let you query which audio 

4modules are currently installed on your system. 

5 

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

11 

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. 

16 

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. 

20 

21 

22## Functions 

23 

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. 

35 

36 

37## Command line script 

38 

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: 

49 

50```text 

51Status of audio packages on this machine: 

52----------------------------------------- 

53 

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) 

67 

68F: file I/O, D: audio device 

69 

70There is no need to install additional audio packages. 

71``` 

72 

73For instructions on specific packages, run `audiomodules` with the name of 

74the package supplied as argument: 

75 

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. 

88 

89First, install the following packages: 

90 

91sudo apt install libsndfile1 libsndfile1-dev libffi-dev 

92 

93Install the soundfile module with pip: 

94 

95sudo pip install SoundFile 

96 

97or alternatively from your distribution's package: 

98 

99sudo apt install python3-soundfile 

100``` 

101 

102Running 

103```sh 

104audiomodules --help 

105``` 

106prints 

107```text 

108usage: audiomodules [--version] [--help] [PACKAGE] 

109 

110Installation status and instructions of python audio packages. 

111 

112optional arguments: 

113 --help show this help message and exit 

114 --version show version number and exit 

115 PACKAGE show installation instructions for PACKAGE 

116 

117version 2.2.0 by Benda-Lab (2015-2024) 

118``` 

119 

120## Links 

121 

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 

124 

125For an overview on packages for playing and recording audio, see 

126https://realpython.com/playing-and-recording-sound-python/ 

127 

128""" 

129 

130import sys 

131import os 

132 

133from .version import __version__, __year__ 

134 

135 

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

140 

141audio_installed = [] 

142""" List of installed audio modules. """ 

143 

144audio_infos = {} 

145""" Dictionary with information about all supported audio modules. 

146Keys are the module names, values are the informations. """ 

147 

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

152 

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

157 

158audio_pip_packages = {} 

159""" Dictionary with pip package names of the audio modules. 

160Keys are the module names, values are pip package names. """ 

161 

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

166 

167audio_deb_packages = {} 

168""" Dictionary with Linux DEB packages of the audio modules. 

169Keys are the module names, values are the package names. """ 

170 

171audio_rpm_packages = {} 

172""" Dictionary with Linux RPM packages of the audio modules. 

173Keys are the module names, values are the package names. """ 

174 

175audio_brew_packages = {} 

176""" Dictionary with macOS homebrew packages of the audio modules. 

177Keys are the module names, values are the package (formulae) names. """ 

178 

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

182 

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

186 

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

190 

191audio_fileio = [] 

192""" List of audio modules used for reading and writing audio files. """ 

193 

194audio_device = [] 

195""" List of audio modules used for playing and recording sounds on audio devices. """ 

196 

197 

198# probe for available audio modules: 

199 

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

209 

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

221 

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

236 

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

253 

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

269 

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

345 

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

363 

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

381 

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 

402 

403pip install PyAudio-0.2.11-cp39-cp39-win_amd64.whl 

404 

405replace the wheel file name by the one you downloaded.""" 

406 

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

421 

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

437 

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

453 

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

466 

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

479 

480 

481def installed_modules(func='all'): 

482 """Installed audio modules. 

483 

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. 

487 

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. 

494  

495 Returns 

496 ------- 

497 mods: list of strings 

498 List of installed audio modules of the requested function. 

499 

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 

510 

511 

512def available_modules(func='all'): 

513 """Installed and enabled audio modules. 

514 

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. 

518 

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. 

525  

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

538 

539 

540def unavailable_modules(func='all'): 

541 """Audio modules that are not installed and not enabled. 

542 

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. 

549  

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

562 

563 

564def disable_module(module=None): 

565 """Disable an audio module. 

566 

567 A disabled module is not used by the audioio functions and classes. 

568 To disable all modules except one, call `select_module()`. 

569  

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. 

575 

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 

585 

586 

587def enable_module(module=None): 

588 """Enable audio modules provided they are installed. 

589  

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. 

595 

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) 

605 

606 

607def select_module(module): 

608 """Select (enable) a single audio module and disable all others. 

609 

610 Undo by calling `enable_module()` without arguments. 

611  

612 Parameters 

613 ---------- 

614 module: string 

615 Name of the module to be selected. 

616 

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. 

622 

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 

632 

633 

634def list_modules(module='all', availability=True): 

635 """Print list of all supported modules and their installation status. 

636  

637 Modules that are not installed but are recommended are marked 

638 with an all uppercase "NOT installed". 

639 

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. 

649 

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}') 

674 

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) 

693 

694 

695def missing_modules(func='all'): 

696 """Missing audio modules that are recommended to be installed. 

697 

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. 

704  

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 

724 

725 

726def missing_modules_instructions(func='all'): 

727 """Print installation instructions for missing but useful audio modules. 

728 

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

746 

747 

748def installation_instruction(module): 

749 """Instructions on how to install a specific audio module. 

750 

751 Parameters 

752 ---------- 

753 module: string 

754 The name of the module for which an instruction should be printed. 

755  

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 

769 

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 

775 

776 install_conda = "conda install" 

777 

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

805 

806 pip_package = audio_pip_packages.get(module, None) 

807 

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 

818 

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}' 

822 

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}' 

829 

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 

834 

835 info = audio_infos.get(module, None) 

836 

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 

843 

844 return msg 

845 

846 

847def main(*args): 

848 """ Command line program for listing installation status of audio modules. 

849 

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. 

860 

861 The '--help' argument prints out a help message: 

862 ```sh 

863 > audiomodules --help 

864 ``` 

865 

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 

889 

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('') 

908 

909 

910if __name__ == "__main__": 

911 main(*sys.argv[1:])