Coverage for src/audioio/audiomodules.py: 79%

405 statements  

« prev     ^ index     » next       coverage.py v7.16.0, created at 2026-09-01 19:42 +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 wavpack = ctypes.CDLL('libwavpack.so.1') 

274 wavpack.WavpackOpenFileInput.restype = ctypes.c_void_p 

275 wavpack.WavpackGetNumSamples64.restype = ctypes.c_int64 

276 wavpack.WavpackGetWrapperData.restype = ctypes.POINTER(ctypes.c_ubyte) 

277 wavpack.WavpackSeekSample64.argtypes = [ctypes.c_void_p, ctypes.c_int64] 

278 wavpack.WavpackUnpackSamples.argtypes = [ctypes.c_void_p, 

279 ctypes.POINTER(ctypes.c_int32), 

280 ctypes.c_uint32] 

281 audio_modules['wavpack'] = True 

282 audio_installed.append('wavpack') 

283except (OSError, AttributeError): # no library or too old 

284 audio_modules['wavpack'] = False 

285audio_deb_packages['wavpack'] = 'libwavpack1' 

286audio_rpm_packages['wavpack'] = 'wavpack-libs' 

287audio_brew_packages['wavpack'] = 'wavpack' 

288audio_infos['wavpack'] = """The wavpack library reads WavPack files, a lossless compression of audio data. 

289It is called via ctypes, no python package is needed. 

290For documentation see https://www.wavpack.com""" 

291 

292audio_fileio.append('audioread') 

293try: 

294 import audioread 

295 audio_modules['audioread'] = True 

296 audio_installed.append('audioread') 

297except ImportError: 

298 audio_modules['audioread'] = False 

299audio_pip_packages['audioread'] = 'audioread' 

300audio_conda_packages['audioread'] = '-c conda-forge audioread' 

301audio_deb_packages['audioread'] = 'python3-audioread' 

302audio_rpm_packages['audioread'] = 'python3-audioread' 

303audio_required_deb_packages['audioread'] = ['ffmpeg', 'libavcodec-extra'] 

304audio_required_rpm_packages['audioread'] = ['ffmpeg', 'ffmpeg-devel', 'libavcodec-extra'] 

305audio_required_brew_packages['audioread'] = ['libav --with-libvorbis --with-sdl --with-theora', 'ffmpeg --with-libvorbis --with-sdl2 --with-theora'] 

306audio_infos['audioread'] = """The audioread package uses libav (https://libav.org/) or ffmpeg (https://ffmpeg.org/) to make mpeg files readable. 

307Install this package for reading mpeg files. 

308For documentation see https://github.com/beetbox/audioread""" 

309 

310audio_fileio.append('pydub') 

311try: 

312 import pydub 

313 audio_modules['pydub'] = True 

314 audio_installed.append('pydub') 

315except ImportError: 

316 audio_modules['pydub'] = False 

317audio_pip_packages['pydub'] = 'pydub' 

318audio_conda_packages['pydub'] = '-c conda-forge pydub' 

319audio_deb_packages['pydub'] = 'python3-pydub' 

320audio_rpm_packages['pydub'] = 'python3-pydub' 

321audio_required_deb_packages['pydub'] = ['ffmpeg', 'libavcodec-extra'] 

322audio_required_rpm_packages['pydub'] = ['ffmpeg', 'ffmpeg-devel', 'libavcodec-extra'] 

323audio_required_brew_packages['pydub'] = ['libav --with-libvorbis --with-sdl --with-theora', 'ffmpeg --with-libvorbis --with-sdl2 --with-theora'] 

324audio_infos['pydub'] = """The pydub package uses libav (https://libav.org/) or ffmpeg (https://ffmpeg.org/) to make mpeg files readable and writeable. 

325Install this package if you need to write mpeg files. 

326For documentation see https://github.com/jiaaro/pydub""" 

327 

328audio_device.append('pyaudio') 

329try: 

330 import pyaudio 

331 audio_modules['pyaudio'] = True 

332 audio_installed.append('pyaudio') 

333except ImportError: 

334 audio_modules['pyaudio'] = False 

335audio_pip_packages['pyaudio'] = 'PyAudio' 

336audio_conda_packages['pyaudio'] = 'pyaudio' 

337audio_deb_packages['pyaudio'] = 'python3-pyaudio # WARNING: broken on Ubuntu with python 3.10, use pip instead' 

338audio_rpm_packages['pyaudio'] = 'python3-pyaudio' 

339audio_required_deb_packages['pyaudio'] = ['libportaudio2'] 

340audio_required_rpm_packages['pyaudio'] = ['libportaudio', 'portaudio-devel'] 

341audio_required_brew_packages['pyaudio'] = ['portaudio'] 

342audio_infos['pyaudio'] = """The pyaudio package is a wrapper of the portaudio library (http://www.portaudio.com). 

343This is an alternative to the sounddevice package with similar properties. 

344For documentation see https://people.csail.mit.edu/hubert/pyaudio.""" 

345audio_instructions_windows['pyaudio'] = """Download an appropriate (latest version, 32 or 64 bit) wheel from 

346<https://www.lfd.uci.edu/~gohlke/pythonlibs/#pyaudio>. Install this file with pip, 

347that is go to the folder where the wheel file is downloaded and run 

348 

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

350 

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

352 

353audio_device.append('sounddevice') 

354try: 

355 import sounddevice 

356 audio_modules['sounddevice'] = True 

357 audio_installed.append('sounddevice') 

358except ImportError: 

359 audio_modules['sounddevice'] = False 

360audio_pip_packages['sounddevice'] = 'sounddevice' 

361audio_conda_packages['sounddevice'] = '-c conda-forge python-sounddevice' 

362audio_required_deb_packages['sounddevice'] = ['libportaudio2', 'python3-cffi'] 

363audio_required_rpm_packages['sounddevice'] = ['libportaudio', 'portaudio-devel', 'python3-cffi'] 

364audio_required_brew_packages['sounddevice'] = ['portaudio'] 

365audio_infos['sounddevice'] = """The sounddevice package is a wrapper of the portaudio library (http://www.portaudio.com).  

366For documentation see https://python-sounddevice.readthedocs.io""" 

367 

368audio_device.append('simpleaudio') 

369try: 

370 import simpleaudio 

371 audio_modules['simpleaudio'] = True 

372 audio_installed.append('simpleaudio') 

373except ImportError: 

374 audio_modules['simpleaudio'] = False 

375audio_pip_packages['simpleaudio'] = 'simpleaudio' 

376audio_rpm_packages['simpleaudio'] = 'python3-simpleaudio' 

377audio_required_deb_packages['simpleaudio'] = ['python3-dev', 'libasound2-dev'] 

378audio_required_rpm_packages['simpleaudio'] = ['python3-devel', 'alsa-lib', 'alsa-lib-devel'] 

379audio_infos['simpleaudio'] = """The simpleaudio package is a lightweight package 

380for cross-platform audio playback. 

381Unfortunately, this package is no longer maintained. 

382For documentation see https://simpleaudio.readthedocs.io""" 

383 

384audio_device.append('soundcard') 

385try: 

386 import soundcard 

387 audio_modules['soundcard'] = True 

388 audio_installed.append('soundcard') 

389except ImportError: 

390 audio_modules['soundcard'] = False 

391except AssertionError: 

392 audio_modules['soundcard'] = False 

393audio_pip_packages['soundcard'] = 'soundcard' 

394audio_infos['soundcard'] = """SoundCard is a library for playing and recording audio without 

395resorting to a CPython extension. Instead, it is implemented using the 

396wonderful CFFI and the native audio libraries of Linux, Windows and 

397macOS. 

398For documentation see https://github.com/bastibe/SoundCard""" 

399 

400audio_device.append('ossaudiodev') 

401try: 

402 import ossaudiodev 

403 audio_modules['ossaudiodev'] = True 

404 audio_installed.append('ossaudiodev') 

405except ImportError: 

406 audio_modules['ossaudiodev'] = False 

407audio_required_deb_packages['ossaudiodev'] = ['osspd'] 

408audio_infos['ossaudiodev'] = """The ossaudiodev module is part of the python standard library and 

409provides simple support for sound playback under Linux based on the (outdated) OSS system. 

410You most likely want to install the simpleaudio or the soundfile package for better performance. 

411For documentation see https://docs.python.org/3.8/library/ossaudiodev.html""" 

412 

413audio_device.append('winsound') 

414try: 

415 import winsound 

416 audio_modules['winsound'] = True 

417 audio_installed.append('winsound') 

418except ImportError: 

419 audio_modules['winsound'] = False 

420audio_infos['winsound'] = """The winsound module is part of the python standard library and 

421provides simple support for sound playback under Windows. If possible, 

422install the simpleaudio package in addition for better performance. 

423For documentation see https://docs.python.org/3.6/library/winsound.html and 

424https://mail.python.org/pipermail/tutor/2012-September/091529.html""" 

425 

426 

427def installed_modules(func='all'): 

428 """Installed audio modules. 

429 

430 By default all installed modules are available. With 

431 `disable_module()`, `enable_module()` and `select_module()` 

432 the availability of installed modules can be controlled. 

433 

434 Parameters 

435 ---------- 

436 func: string 

437 'all': all installed audio modules. 

438 'fileio': installed audio modules used for file I/O. 

439 'device': installed audio modules used for playing and recording sounds. 

440  

441 Returns 

442 ------- 

443 mods: list of strings 

444 List of installed audio modules of the requested function. 

445 

446 See Also 

447 -------- 

448 available_modules() 

449 """ 

450 if func == 'fileio': 

451 return [module for module in audio_fileio if module in audio_installed] 

452 elif func == 'device': 

453 return [module for module in audio_device if module in audio_installed] 

454 else: 

455 return audio_installed 

456 

457 

458def available_modules(func='all'): 

459 """Installed and enabled audio modules. 

460 

461 By default all installed modules are available. With 

462 `disable_module()`, `enable_module()` and `select_module()` 

463 the availability of installed modules can be controlled. 

464 

465 Parameters 

466 ---------- 

467 func: string 

468 'all': all installed audio modules. 

469 'fileio': installed audio modules used for file I/O. 

470 'device': installed audio modules used for playing and recording sounds. 

471  

472 Returns 

473 ------- 

474 mods: list of strings 

475 List of available, i.e. installed and enabled, audio modules 

476 of the requested function. 

477 """ 

478 if func == 'fileio': 

479 return [module for module in audio_fileio if audio_modules[module]] 

480 elif func == 'device': 

481 return [module for module in audio_device if audio_modules[module]] 

482 else: 

483 return [module for module in audio_installed if audio_modules[module]] 

484 

485 

486def unavailable_modules(func='all'): 

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

488 

489 Parameters 

490 ---------- 

491 func: string 

492 'all': all installed audio modules. 

493 'fileio': installed audio modules used for file I/O. 

494 'device': installed audio modules used for playing and recording sounds. 

495  

496 Returns 

497 ------- 

498 mods: list of strings 

499 List of not available, i.e. not installed and not enabled, audio modules 

500 of the requested function. 

501 """ 

502 if func == 'fileio': 

503 return [module for module in audio_fileio if not audio_modules[module]] 

504 elif func == 'device': 

505 return [module for module in audio_device if not audio_modules[module]] 

506 else: 

507 return [module for module in audio_modules.keys() if not audio_modules[module]] 

508 

509 

510def disable_module(module=None): 

511 """Disable an audio module. 

512 

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

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

515  

516 Parameters 

517 ---------- 

518 module: string or None 

519 Name of the module to be disabled as it appears in `available_modules()`. 

520 If None disable all installed audio modules. 

521 

522 See Also 

523 -------- 

524 enable_module(), select_module(), available_modules(), list_modules() 

525 """ 

526 if module is None: 

527 for module in audio_installed: 

528 audio_modules[module] = False 

529 elif module in audio_modules: 

530 audio_modules[module] = False 

531 

532 

533def enable_module(module=None): 

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

535  

536 Parameters 

537 ---------- 

538 module: string or None 

539 Name of the module to be (re)enabled. 

540 If None enable all installed audio modules. 

541 

542 See Also 

543 -------- 

544 disable_module(), available_modules(), list_modules() 

545 """ 

546 if module is None: 

547 for module in audio_installed: 

548 audio_modules[module] = True 

549 elif module in audio_modules: 

550 audio_modules[module] = (module in audio_installed) 

551 

552 

553def select_module(module): 

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

555 

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

557  

558 Parameters 

559 ---------- 

560 module: string 

561 Name of the module to be selected. 

562 

563 Returns 

564 ------- 

565 selected: bool 

566 False if the module can not be selected, because it is not installed. 

567 In this case the other modules are not disabled. 

568 

569 See Also 

570 -------- 

571 enable_module(), disable_module(), available_modules(), list_modules() 

572 """ 

573 if module not in audio_installed: 

574 return False 

575 for mod in audio_installed: 

576 audio_modules[mod] = (mod == module) 

577 return True 

578 

579 

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

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

582  

583 Modules that are not installed but are recommended are marked 

584 with an all uppercase "NOT installed". 

585 

586 Parameters 

587 ---------- 

588 module: string 

589 If 'all' list all modules. 

590 If 'fileio' list all modules used for file I/O. 

591 If 'device' list all modules used for playing and recording sounds. 

592 Otherwise list only the specified module. 

593 availability: bool 

594 Mark availability of each module by an asterisk. 

595 

596 See Also 

597 -------- 

598 installed_modules() 

599 missing_modules() 

600 missing_modules_instructions() 

601 """ 

602 def print_module(module, missing, print_type): 

603 audio_avail = '' 

604 if availability: 

605 audio_avail = '* ' if audio_modules[module] else ' ' 

606 audio_type = '' 

607 if print_type: 

608 if module in audio_fileio: 

609 audio_type += 'F' 

610 if module in audio_device: 

611 audio_type += 'D' 

612 if len(audio_type) > 0: 

613 audio_type = f' ({audio_type})' 

614 if module in audio_installed: 

615 print(f'{audio_avail}{module:<17s} is installed{audio_type}') 

616 elif module in missing: 

617 print(f'{audio_avail}{module:<17s} NOT installed{audio_type}') 

618 else: 

619 print(f'{audio_avail}{module:<17s} not installed{audio_type}') 

620 

621 missing = missing_modules() 

622 if module not in ['all', 'fileio', 'device']: 

623 print_module(module, missing, True) 

624 else: 

625 print_type = (module == 'all') 

626 modules = sorted(audio_modules.keys()) 

627 if module in ['all', 'fileio']: 

628 for mod in audio_fileio: 

629 print_module(mod, missing, print_type) 

630 modules.remove(mod) 

631 if module in ['all', 'device']: 

632 for mod in audio_device: 

633 if mod in modules: 

634 print_module(mod, missing, print_type) 

635 modules.remove(mod) 

636 if module == 'all': 

637 for mod in modules: 

638 print_module(mod, missing, print_type) 

639 

640 

641def missing_modules(func='all'): 

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

643 

644 Parameters 

645 ---------- 

646 func: string 

647 'all': missing audio modules of all functions. 

648 'fileio': missing audio modules for file I/O. 

649 'device': missing audio modules for playing and recording sounds. 

650  

651 Returns 

652 ------- 

653 mods: list of strings 

654 List of missing audio modules of the requested function. 

655 """ 

656 mods = [] 

657 if func in ['all', 'fileio']: 

658 if 'soundfile' not in audio_installed and \ 

659 'wavefile' not in audio_installed: 

660 mods.append('soundfile') 

661 if 'audioread' not in audio_installed: 

662 mods.append('audioread') 

663 if 'pydub' not in audio_installed: 

664 mods.append('pydub') 

665 if func in ['all', 'device']: 

666 if 'pyaudio' not in audio_installed and \ 

667 'sounddevice' not in audio_installed: 

668 mods.append('sounddevice') 

669 return mods 

670 

671 

672def missing_modules_instructions(func='all'): 

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

674 

675 Parameters 

676 ---------- 

677 func: string 

678 'all': missing audio modules of all functions. 

679 'fileio': missing audio modules for file I/O. 

680 'device': missing audio modules for playing and recording sounds. 

681 """ 

682 mods = missing_modules(func) 

683 if len(mods) > 0 : 

684 print('For better performance you should install the following modules:') 

685 for mod in mods: 

686 print() 

687 print(f'{mod}:') 

688 print('-'*(len(mod)+1)) 

689 print(installation_instruction(mod)) 

690 else: 

691 print('There is no need to install additional audio packages.') 

692 

693 

694def installation_instruction(module): 

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

696 

697 Parameters 

698 ---------- 

699 module: string 

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

701  

702 Returns 

703 ------- 

704 msg: multi-line string 

705 Installation instruction for the requested module. 

706 """ 

707 install_package_deb = "sudo apt install" 

708 install_package_rpm = "dnf install" 

709 install_package_brew = "brew install" 

710 install_package = None 

711 package = None 

712 required_packages = None 

713 multiline = False 

714 instruction = None 

715 

716 install_pip_deb = "sudo pip install" 

717 install_pip_rpm = "pip install" 

718 install_pip_osx = "pip install" 

719 install_pip_win = "pip install" 

720 install_pip = install_pip_deb 

721 

722 install_conda = "conda install" 

723 

724 # check operating system: 

725 if sys.platform[0:5] == "linux": 

726 if os.path.exists('/etc/redhat-release') or os.path.exists('/etc/fedora-release'): 

727 install_package = install_package_rpm 

728 install_pip = install_pip_rpm 

729 package = audio_rpm_packages.get(module, None) 

730 required_packages = audio_required_rpm_packages.get(module, None) 

731 else: 

732 install_package = install_package_deb 

733 package = audio_deb_packages.get(module, None) 

734 required_packages = audio_required_deb_packages.get(module, None) 

735 instruction = audio_instructions_linux.get(module, None) 

736 elif sys.platform == "darwin": 

737 install_package = install_package_brew 

738 install_pip = install_pip_osx 

739 package = audio_brew_packages.get(module, None) 

740 required_packages = audio_required_brew_packages.get(module, None) 

741 multiline = True 

742 elif sys.platform[0:3] == "win": 

743 install_package = '' 

744 install_pip = install_pip_win 

745 instruction = audio_instructions_windows.get(module, None) 

746 # check conda: 

747 conda = "CONDA_DEFAULT_ENV" in os.environ 

748 conda_package = audio_conda_packages.get(module, None) 

749 if conda: 

750 install_pip = install_pip.replace('sudo ', '') 

751 

752 pip_package = audio_pip_packages.get(module, None) 

753 

754 req_inst = None 

755 if required_packages is not None: 

756 if multiline: 

757 ps = '\n'.join([install_package + ' ' + p for p in required_packages]) 

758 else: 

759 ps = install_package + ' ' + ' '.join(required_packages) 

760 if pip_package is None and package is None: 

761 req_inst = 'Install the following packages:\n\n' + ps 

762 else: 

763 req_inst = 'First, install the following packages:\n\n' + ps 

764 

765 pip_inst = None 

766 if pip_package is not None: 

767 pip_inst = f'Install the {module} module with pip:\n\n{install_pip} {pip_package}' 

768 

769 dist_inst = None 

770 if package is not None: 

771 if pip_inst is None: 

772 dist_inst = f'Install module from your distribution\'s package:\n\n{install_package} {package}' 

773 else: 

774 dist_inst = f'or alternatively from your distribution\'s package:\n\n{install_package} {package}' 

775 

776 conda_inst = None 

777 if conda and conda_package is not None: 

778 conda_inst = f'Install the {module} module with conda:\n\n{install_package} {package}' 

779 req_inst = pip_inst = dist_inst = instruction = None 

780 

781 info = audio_infos.get(module, None) 

782 

783 msg = '' 

784 for s in [info, conda_inst, req_inst, pip_inst, dist_inst, instruction]: 

785 if s is not None: 

786 if len(msg) > 0: 

787 msg += '\n\n' 

788 msg += s 

789 

790 return msg 

791 

792 

793def main(*args): 

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

795 

796 Run this module as a script 

797 ``` 

798 > python -m src.audioio.auidomodules 

799 ``` 

800 or, when the audioio package is installed on your system, simply run 

801 ```sh 

802 > audiomodules 

803 ``` 

804 for an overview of audio packages, their installation status, and recommendations on 

805 how to install further audio packages. 

806 

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

808 ```sh 

809 > audiomodules --help 

810 ``` 

811 

812 Parameters 

813 ---------- 

814 args: list of strings 

815 Command line arguments as provided by sys.argv[1:] 

816 """ 

817 if len(args) == 0: 

818 args = sys.argv[1:] 

819 if len(args) > 0: 

820 if args[0] == '--version': 

821 print(f'version {__version__} by Benda-Lab (2015-{__year__})') 

822 sys.exit(0) 

823 if args[0] == '--help' or args[0] == '-h': 

824 print('usage: audiomodules [--version] [--help] [PACKAGE]') 

825 print('') 

826 print('Installation status and instructions of python audio packages.') 

827 print('') 

828 print('optional arguments:') 

829 print(' --help show this help message and exit') 

830 print(' --version show version number and exit') 

831 print(' PACKAGE show installation instructions for PACKAGE') 

832 print('') 

833 print(f'version {__version__} by Benda-Lab (2015-{__year__})') 

834 return 

835 

836 print('') 

837 if len(args) > 0 : 

838 mod = args[0] 

839 if mod in audio_modules: 

840 print(f'Installation instructions for the {mod} module:') 

841 print('-'*(42+len(mod))) 

842 print(installation_instruction(mod)) 

843 print('') 

844 else: 

845 print('Status of audio packages on this machine:') 

846 print('-'*41) 

847 print('') 

848 list_modules('all', False) 

849 print('') 

850 print('F: file I/O, D: audio device') 

851 print('') 

852 missing_modules_instructions() 

853 print('') 

854 

855 

856if __name__ == "__main__": 

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