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

388 statements  

« prev     ^ index     » next       coverage.py v7.13.1, created at 2026-01-17 21:34 +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) 

59audioread is installed (F) 

60pyaudio is installed (D) 

61sounddevice not installed (D) 

62simpleaudio is installed (D) 

63soundcard is installed (D) 

64ossaudiodev is installed (D) 

65winsound not installed (D) 

66 

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

68 

69There is no need to install additional audio packages. 

70``` 

71 

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

73the package supplied as argument: 

74 

75```sh 

76> audiomodules soundfile 

77``` 

78This produces something like this: 

79```text 

80... 

81Installation instructions for the soundfile module: 

82--------------------------------------------------- 

83The soundfile package is a wrapper of the sndfile library, 

84that supports many different audio file formats. 

85See http://python-soundfile.readthedocs.org for a documentation of the soundfile python wrapper 

86and http://www.mega-nerd.com/libsndfile for details on the sndfile library. 

87 

88First, install the following packages: 

89 

90sudo apt install libsndfile1 libsndfile1-dev libffi-dev 

91 

92Install the soundfile module with pip: 

93 

94sudo pip install SoundFile 

95 

96or alternatively from your distribution's package: 

97 

98sudo apt install python3-soundfile 

99``` 

100 

101Running 

102```sh 

103audiomodules --help 

104``` 

105prints 

106```text 

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

108 

109Installation status and instructions of python audio packages. 

110 

111optional arguments: 

112 --help show this help message and exit 

113 --version show version number and exit 

114 PACKAGE show installation instructions for PACKAGE 

115 

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

117``` 

118 

119## Links 

120 

121For an overview on python modules regarding file I/O see, for example, 

122http://nbviewer.jupyter.org/github/mgeier/python-audio/blob/master/audio-files/index.ipynb 

123 

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

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

126 

127""" 

128 

129import sys 

130import os 

131 

132from .version import __version__, __year__ 

133 

134 

135audio_modules = {} 

136""" Dictionary with availability of various audio modules. 

137Keys are the module names, values are booleans. 

138Based on this dictionary audioio employs functions of installed audio modules. """ 

139 

140audio_installed = [] 

141""" List of installed audio modules. """ 

142 

143audio_infos = {} 

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

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

146 

147audio_instructions_linux = {} 

148""" Dictionary with general installation instructions for linux that 

149are needed in addition to installing some packages. 

150Keys are the module names, values are the instructions. """ 

151 

152audio_instructions_windows = {} 

153""" Dictionary with general installation instructions for windows that 

154are needed in addition to installing some packages. 

155Keys are the module names, values are the instructions. """ 

156 

157audio_pip_packages = {} 

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

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

160 

161audio_conda_packages = {} 

162""" Dictionary with conda package names of the audio modules. 

163Keys are the module names, values are conda package names, 

164optionally with a channel specification. """ 

165 

166audio_deb_packages = {} 

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

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

169 

170audio_rpm_packages = {} 

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

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

173 

174audio_brew_packages = {} 

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

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

177 

178audio_required_deb_packages = {} 

179""" Dictionary with Linux DEB packages required for the audio modules. 

180Keys are the module names, values are lists of string with package names. """ 

181 

182audio_required_rpm_packages = {} 

183""" Dictionary with Linux RPM packages required for the audio modules. 

184Keys are the module names, values are lists of string with package names. """ 

185 

186audio_required_brew_packages = {} 

187""" Dictionary with macOS homebrew packages required for the audio modules. 

188Keys are the module names, values are lists of string with package (formulae) names. """ 

189 

190audio_fileio = [] 

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

192 

193audio_device = [] 

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

195 

196 

197# probe for available audio modules: 

198 

199audio_fileio.append('wave') 

200try: 

201 import wave 

202 audio_modules['wave'] = True 

203 audio_installed.append('wave') 

204except ImportError: 

205 audio_modules['wave'] = False 

206audio_infos['wave'] = """The wave module is part of the standard python library. 

207For documentation see https://docs.python.org/3.8/library/wave.html""" 

208 

209audio_fileio.append('ewave') 

210try: 

211 import ewave 

212 audio_modules['ewave'] = True 

213 audio_installed.append('ewave') 

214except ImportError: 

215 audio_modules['ewave'] = False 

216audio_pip_packages['ewave'] = 'ewave' 

217audio_conda_packages['ewave'] = '-c auto ewave' 

218audio_infos['ewave'] = """The ewave package supports more types of WAV-files than the standard wave module. 

219For documentation see https://github.com/melizalab/py-ewave""" 

220 

221audio_fileio.append('scipy.io.wavfile') 

222try: 

223 from scipy.io import wavfile 

224 audio_modules['scipy.io.wavfile'] = True 

225 audio_installed.append('scipy.io.wavfile') 

226except ImportError: 

227 audio_modules['scipy.io.wavfile'] = False 

228audio_pip_packages['scipy.io.wavfile'] = 'scipy' 

229audio_conda_packages['scipy.io.wavfile'] = 'scipy' 

230audio_deb_packages['scipy.io.wavfile'] = 'python3-scipy' 

231audio_rpm_packages['scipy.io.wavfile'] = 'python3-scipy' 

232audio_brew_packages['scipy.io.wavfile'] = 'scipy' 

233audio_infos['scipy.io.wavfile'] = """The scipy package provides very basic functions for reading WAV files. 

234For documentation see http://docs.scipy.org/doc/scipy/reference/io.html""" 

235 

236audio_fileio.append('soundfile') 

237try: 

238 import soundfile 

239 audio_modules['soundfile'] = True 

240 audio_installed.append('soundfile') 

241except ImportError: 

242 audio_modules['soundfile'] = False 

243audio_pip_packages['soundfile'] = 'SoundFile' 

244audio_conda_packages['soundfile'] = '-c conda-forge soundfile' 

245audio_deb_packages['soundfile'] = 'python3-soundfile' 

246audio_required_deb_packages['soundfile'] = ['libsndfile1', 'libsndfile1-dev', 'libffi-dev'] 

247audio_required_rpm_packages['soundfile'] = ['libsndfile', 'libsndfile-devel', 'libffi-devel'] 

248audio_infos['soundfile'] = """The soundfile package is a wrapper of the sndfile library, 

249that supports many different audio file formats. 

250See http://python-soundfile.readthedocs.org for a documentation of the soundfile python wrapper 

251and http://www.mega-nerd.com/libsndfile for details on the sndfile library.""" 

252 

253audio_fileio.append('wavefile') 

254try: 

255 import wavefile 

256 audio_modules['wavefile'] = True 

257 audio_installed.append('wavefile') 

258except ImportError: 

259 audio_modules['wavefile'] = False 

260audio_pip_packages['wavefile'] = 'wavefile' 

261audio_required_deb_packages['wavefile'] = ['libsndfile1', 'libsndfile1-dev', 'libffi-dev'] 

262audio_required_rpm_packages['wavefile'] = ['libsndfile', 'libsndfile-devel', 'libffi-devel'] 

263audio_required_brew_packages['wavefile'] = ['libsndfile', 'libffi'] 

264audio_infos['wavefile'] = """The wavefile package is a wrapper of the sndfile library, 

265that supports many different audio file formats. 

266See https://github.com/vokimon/python-wavefile for documentation of the wavefile python wrapper 

267and http://www.mega-nerd.com/libsndfile for details on the sndfile library.""" 

268 

269audio_fileio.append('audioread') 

270try: 

271 import audioread 

272 audio_modules['audioread'] = True 

273 audio_installed.append('audioread') 

274except ImportError: 

275 audio_modules['audioread'] = False 

276audio_pip_packages['audioread'] = 'audioread' 

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

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

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

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

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

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

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

284Install this package for reading mpeg files. 

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

286 

287audio_fileio.append('pydub') 

288try: 

289 import pydub 

290 audio_modules['pydub'] = True 

291 audio_installed.append('pydub') 

292except ImportError: 

293 audio_modules['pydub'] = False 

294audio_pip_packages['pydub'] = 'pydub' 

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

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

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

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

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

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

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

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

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

304 

305audio_device.append('pyaudio') 

306try: 

307 import pyaudio 

308 audio_modules['pyaudio'] = True 

309 audio_installed.append('pyaudio') 

310except ImportError: 

311 audio_modules['pyaudio'] = False 

312audio_pip_packages['pyaudio'] = 'PyAudio' 

313audio_conda_packages['pyaudio'] = 'pyaudio' 

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

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

316audio_required_deb_packages['pyaudio'] = ['libportaudio2'] 

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

318audio_required_brew_packages['pyaudio'] = ['portaudio'] 

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

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

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

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

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

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

325 

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

327 

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

329 

330audio_device.append('sounddevice') 

331try: 

332 import sounddevice 

333 audio_modules['sounddevice'] = True 

334 audio_installed.append('sounddevice') 

335except ImportError: 

336 audio_modules['sounddevice'] = False 

337audio_pip_packages['sounddevice'] = 'sounddevice' 

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

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

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

341audio_required_brew_packages['sounddevice'] = ['portaudio'] 

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

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

344 

345audio_device.append('simpleaudio') 

346try: 

347 import simpleaudio 

348 audio_modules['simpleaudio'] = True 

349 audio_installed.append('simpleaudio') 

350except ImportError: 

351 audio_modules['simpleaudio'] = False 

352audio_pip_packages['simpleaudio'] = 'simpleaudio' 

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

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

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

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

357for cross-platform audio playback. 

358Unfortunately, this package is no longer maintained. 

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

360 

361audio_device.append('soundcard') 

362try: 

363 import soundcard 

364 audio_modules['soundcard'] = True 

365 audio_installed.append('soundcard') 

366except ImportError: 

367 audio_modules['soundcard'] = False 

368except AssertionError: 

369 audio_modules['soundcard'] = False 

370audio_pip_packages['soundcard'] = 'soundcard' 

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

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

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

374macOS. 

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

376 

377audio_device.append('ossaudiodev') 

378try: 

379 import ossaudiodev 

380 audio_modules['ossaudiodev'] = True 

381 audio_installed.append('ossaudiodev') 

382except ImportError: 

383 audio_modules['ossaudiodev'] = False 

384audio_required_deb_packages['ossaudiodev'] = ['osspd'] 

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

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

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

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

389 

390audio_device.append('winsound') 

391try: 

392 import winsound 

393 audio_modules['winsound'] = True 

394 audio_installed.append('winsound') 

395except ImportError: 

396 audio_modules['winsound'] = False 

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

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

399install the simpleaudio package in addition for better performance. 

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

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

402 

403 

404def installed_modules(func='all'): 

405 """Installed audio modules. 

406 

407 By default all installed modules are available. With 

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

409 the availability of installed modules can be controlled. 

410 

411 Parameters 

412 ---------- 

413 func: string 

414 'all': all installed audio modules. 

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

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

417  

418 Returns 

419 ------- 

420 mods: list of strings 

421 List of installed audio modules of the requested function. 

422 

423 See Also 

424 -------- 

425 available_modules() 

426 """ 

427 if func == 'fileio': 

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

429 elif func == 'device': 

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

431 else: 

432 return audio_installed 

433 

434 

435def available_modules(func='all'): 

436 """Installed and enabled audio modules. 

437 

438 By default all installed modules are available. With 

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

440 the availability of installed modules can be controlled. 

441 

442 Parameters 

443 ---------- 

444 func: string 

445 'all': all installed audio modules. 

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

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

448  

449 Returns 

450 ------- 

451 mods: list of strings 

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

453 of the requested function. 

454 """ 

455 if func == 'fileio': 

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

457 elif func == 'device': 

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

459 else: 

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

461 

462 

463def unavailable_modules(func='all'): 

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

465 

466 Parameters 

467 ---------- 

468 func: string 

469 'all': all installed audio modules. 

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

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

472  

473 Returns 

474 ------- 

475 mods: list of strings 

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

477 of the requested function. 

478 """ 

479 if func == 'fileio': 

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

481 elif func == 'device': 

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

483 else: 

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

485 

486 

487def disable_module(module=None): 

488 """Disable an audio module. 

489 

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

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

492  

493 Parameters 

494 ---------- 

495 module: string or None 

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

497 If None disable all installed audio modules. 

498 

499 See Also 

500 -------- 

501 enable_module(), select_module(), available_modules(), list_modules() 

502 """ 

503 if module is None: 

504 for module in audio_installed: 

505 audio_modules[module] = False 

506 elif module in audio_modules: 

507 audio_modules[module] = False 

508 

509 

510def enable_module(module=None): 

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

512  

513 Parameters 

514 ---------- 

515 module: string or None 

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

517 If None enable all installed audio modules. 

518 

519 See Also 

520 -------- 

521 disable_module(), available_modules(), list_modules() 

522 """ 

523 if module is None: 

524 for module in audio_installed: 

525 audio_modules[module] = True 

526 elif module in audio_modules: 

527 audio_modules[module] = (module in audio_installed) 

528 

529 

530def select_module(module): 

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

532 

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

534  

535 Parameters 

536 ---------- 

537 module: string 

538 Name of the module to be selected. 

539 

540 Returns 

541 ------- 

542 selected: bool 

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

544 In this case the other modules are not disabled. 

545 

546 See Also 

547 -------- 

548 enable_module(), disable_module(), available_modules(), list_modules() 

549 """ 

550 if module not in audio_installed: 

551 return False 

552 for mod in audio_installed: 

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

554 return True 

555 

556 

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

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

559  

560 Modules that are not installed but are recommended are marked 

561 with an all uppercase "NOT installed". 

562 

563 Parameters 

564 ---------- 

565 module: string 

566 If 'all' list all modules. 

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

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

569 Otherwise list only the specified module. 

570 availability: bool 

571 Mark availability of each module by an asterisk. 

572 

573 See Also 

574 -------- 

575 installed_modules() 

576 missing_modules() 

577 missing_modules_instructions() 

578 """ 

579 def print_module(module, missing, print_type): 

580 audio_avail = '' 

581 if availability: 

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

583 audio_type = '' 

584 if print_type: 

585 if module in audio_fileio: 

586 audio_type += 'F' 

587 if module in audio_device: 

588 audio_type += 'D' 

589 if len(audio_type) > 0: 

590 audio_type = f' ({audio_type})' 

591 if module in audio_installed: 

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

593 elif module in missing: 

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

595 else: 

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

597 

598 missing = missing_modules() 

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

600 print_module(module, missing, True) 

601 else: 

602 print_type = (module == 'all') 

603 modules = sorted(audio_modules.keys()) 

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

605 for mod in audio_fileio: 

606 print_module(mod, missing, print_type) 

607 modules.remove(mod) 

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

609 for mod in audio_device: 

610 if mod in modules: 

611 print_module(mod, missing, print_type) 

612 modules.remove(mod) 

613 if module == 'all': 

614 for mod in modules: 

615 print_module(mod, missing, print_type) 

616 

617 

618def missing_modules(func='all'): 

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

620 

621 Parameters 

622 ---------- 

623 func: string 

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

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

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

627  

628 Returns 

629 ------- 

630 mods: list of strings 

631 List of missing audio modules of the requested function. 

632 """ 

633 mods = [] 

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

635 if 'soundfile' not in audio_installed and \ 

636 'wavefile' not in audio_installed: 

637 mods.append('soundfile') 

638 if 'audioread' not in audio_installed: 

639 mods.append('audioread') 

640 if 'pydub' not in audio_installed: 

641 mods.append('pydub') 

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

643 if 'pyaudio' not in audio_installed and \ 

644 'sounddevice' not in audio_installed: 

645 mods.append('sounddevice') 

646 return mods 

647 

648 

649def missing_modules_instructions(func='all'): 

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

651 

652 Parameters 

653 ---------- 

654 func: string 

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

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

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

658 """ 

659 mods = missing_modules(func) 

660 if len(mods) > 0 : 

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

662 for mod in mods: 

663 print() 

664 print(f'{mod}:') 

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

666 print(installation_instruction(mod)) 

667 else: 

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

669 

670 

671def installation_instruction(module): 

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

673 

674 Parameters 

675 ---------- 

676 module: string 

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

678  

679 Returns 

680 ------- 

681 msg: multi-line string 

682 Installation instruction for the requested module. 

683 """ 

684 install_package_deb = "sudo apt install" 

685 install_package_rpm = "dnf install" 

686 install_package_brew = "brew install" 

687 install_package = None 

688 package = None 

689 required_packages = None 

690 multiline = False 

691 instruction = None 

692 

693 install_pip_deb = "sudo pip install" 

694 install_pip_rpm = "pip install" 

695 install_pip_osx = "pip install" 

696 install_pip_win = "pip install" 

697 install_pip = install_pip_deb 

698 

699 install_conda = "conda install" 

700 

701 # check operating system: 

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

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

704 install_package = install_package_rpm 

705 install_pip = install_pip_rpm 

706 package = audio_rpm_packages.get(module, None) 

707 required_packages = audio_required_rpm_packages.get(module, None) 

708 else: 

709 install_package = install_package_deb 

710 package = audio_deb_packages.get(module, None) 

711 required_packages = audio_required_deb_packages.get(module, None) 

712 instruction = audio_instructions_linux.get(module, None) 

713 elif sys.platform == "darwin": 

714 install_package = install_package_brew 

715 install_pip = install_pip_osx 

716 package = audio_brew_packages.get(module, None) 

717 required_packages = audio_required_brew_packages.get(module, None) 

718 multiline = True 

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

720 install_package = '' 

721 install_pip = install_pip_win 

722 instruction = audio_instructions_windows.get(module, None) 

723 # check conda: 

724 conda = "CONDA_DEFAULT_ENV" in os.environ 

725 conda_package = audio_conda_packages.get(module, None) 

726 if conda: 

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

728 

729 pip_package = audio_pip_packages.get(module, None) 

730 

731 req_inst = None 

732 if required_packages is not None: 

733 if multiline: 

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

735 else: 

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

737 if pip_package is None and package is None: 

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

739 else: 

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

741 

742 pip_inst = None 

743 if pip_package is not None: 

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

745 

746 dist_inst = None 

747 if package is not None: 

748 if pip_inst is None: 

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

750 else: 

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

752 

753 conda_inst = None 

754 if conda and conda_package is not None: 

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

756 req_inst = pip_inst = dist_inst = instruction = None 

757 

758 info = audio_infos.get(module, None) 

759 

760 msg = '' 

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

762 if s is not None: 

763 if len(msg) > 0: 

764 msg += '\n\n' 

765 msg += s 

766 

767 return msg 

768 

769 

770def main(*args): 

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

772 

773 Run this module as a script 

774 ``` 

775 > python -m src.audioio.auidomodules 

776 ``` 

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

778 ```sh 

779 > audiomodules 

780 ``` 

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

782 how to install further audio packages. 

783 

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

785 ```sh 

786 > audiomodules --help 

787 ``` 

788 

789 Parameters 

790 ---------- 

791 args: list of strings 

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

793 """ 

794 if len(args) == 0: 

795 args = sys.argv[1:] 

796 if len(args) > 0: 

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

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

799 sys.exit(0) 

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

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

802 print('') 

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

804 print('') 

805 print('optional arguments:') 

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

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

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

809 print('') 

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

811 return 

812 

813 print('') 

814 if len(args) > 0 : 

815 mod = args[0] 

816 if mod in audio_modules: 

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

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

819 print(installation_instruction(mod)) 

820 print('') 

821 else: 

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

823 print('-'*41) 

824 print('') 

825 list_modules('all', False) 

826 print('') 

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

828 print('') 

829 missing_modules_instructions() 

830 print('') 

831 

832 

833if __name__ == "__main__": 

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