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

388 statements  

« prev     ^ index     » next       coverage.py v7.6.3, created at 2024-10-15 07:29 +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 

40```sh 

41> python -m src.audioio.auidomodules 

42``` 

43or, when 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 

131from .version import __version__, __year__ 

132 

133 

134audio_modules = {} 

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

136Keys are the module names, values are booleans. 

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

138 

139audio_installed = [] 

140""" List of installed audio modules. """ 

141 

142audio_infos = {} 

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

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

145 

146audio_instructions_linux = {} 

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

148are needed in addition to installing some packages. 

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

150 

151audio_instructions_windows = {} 

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

153are needed in addition to installing some packages. 

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

155 

156audio_pip_packages = {} 

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

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

159 

160audio_conda_packages = {} 

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

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

163optionally with a channel specification. """ 

164 

165audio_deb_packages = {} 

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

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

168 

169audio_rpm_packages = {} 

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

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

172 

173audio_brew_packages = {} 

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

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

176 

177audio_required_deb_packages = {} 

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

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

180 

181audio_required_rpm_packages = {} 

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

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

184 

185audio_required_brew_packages = {} 

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

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

188 

189audio_fileio = [] 

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

191 

192audio_device = [] 

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

194 

195 

196# probe for available audio modules: 

197 

198audio_fileio.append('wave') 

199try: 

200 import wave 

201 audio_modules['wave'] = True 

202 audio_installed.append('wave') 

203except ImportError: 

204 audio_modules['wave'] = False 

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

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

207 

208audio_fileio.append('ewave') 

209try: 

210 import ewave 

211 audio_modules['ewave'] = True 

212 audio_installed.append('ewave') 

213except ImportError: 

214 audio_modules['ewave'] = False 

215audio_pip_packages['ewave'] = 'ewave' 

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

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

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

219 

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

221try: 

222 from scipy.io import wavfile 

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

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

225except ImportError: 

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

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

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

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

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

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

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

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

234 

235audio_fileio.append('soundfile') 

236try: 

237 import soundfile 

238 audio_modules['soundfile'] = True 

239 audio_installed.append('soundfile') 

240except ImportError: 

241 audio_modules['soundfile'] = False 

242audio_pip_packages['soundfile'] = 'SoundFile' 

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

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

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

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

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

248that supports many different audio file formats. 

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

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

251 

252audio_fileio.append('wavefile') 

253try: 

254 import wavefile 

255 audio_modules['wavefile'] = True 

256 audio_installed.append('wavefile') 

257except ImportError: 

258 audio_modules['wavefile'] = False 

259audio_pip_packages['wavefile'] = 'wavefile' 

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

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

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

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

264that supports many different audio file formats. 

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

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

267 

268audio_fileio.append('audioread') 

269try: 

270 import audioread 

271 audio_modules['audioread'] = True 

272 audio_installed.append('audioread') 

273except ImportError: 

274 audio_modules['audioread'] = False 

275audio_pip_packages['audioread'] = 'audioread' 

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

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

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

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

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

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

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

283Install this package for reading mpeg files. 

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

285 

286audio_fileio.append('pydub') 

287try: 

288 import pydub 

289 audio_modules['pydub'] = True 

290 audio_installed.append('pydub') 

291except ImportError: 

292 audio_modules['pydub'] = False 

293audio_pip_packages['pydub'] = 'pydub' 

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

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

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

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

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

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

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

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

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

303 

304audio_device.append('pyaudio') 

305try: 

306 import pyaudio 

307 audio_modules['pyaudio'] = True 

308 audio_installed.append('pyaudio') 

309except ImportError: 

310 audio_modules['pyaudio'] = False 

311audio_pip_packages['pyaudio'] = 'PyAudio' 

312audio_conda_packages['pyaudio'] = 'pyaudio' 

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

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

315audio_required_deb_packages['pyaudio'] = ['libportaudio2', 'portaudio19-dev'] 

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

317audio_required_brew_packages['pyaudio'] = ['portaudio'] 

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

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

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

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

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

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

324 

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

326 

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

328 

329audio_device.append('sounddevice') 

330try: 

331 import sounddevice 

332 audio_modules['sounddevice'] = True 

333 audio_installed.append('sounddevice') 

334except ImportError: 

335 audio_modules['sounddevice'] = False 

336audio_pip_packages['sounddevice'] = 'sounddevice' 

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

338audio_required_deb_packages['sounddevice'] = ['libportaudio2', 'portaudio19-dev', 'python3-cffi'] 

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

340audio_required_brew_packages['sounddevice'] = ['portaudio'] 

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

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

343 

344audio_device.append('simpleaudio') 

345try: 

346 import simpleaudio 

347 audio_modules['simpleaudio'] = True 

348 audio_installed.append('simpleaudio') 

349except ImportError: 

350 audio_modules['simpleaudio'] = False 

351audio_pip_packages['simpleaudio'] = 'simpleaudio' 

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

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

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

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

356for cross-platform audio playback. 

357Unfortunately, this package is no longer maintained. 

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

359 

360audio_device.append('soundcard') 

361try: 

362 import soundcard 

363 audio_modules['soundcard'] = True 

364 audio_installed.append('soundcard') 

365except ImportError: 

366 audio_modules['soundcard'] = False 

367except AssertionError: 

368 audio_modules['soundcard'] = False 

369audio_pip_packages['soundcard'] = 'soundcard' 

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

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

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

373macOS. 

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

375 

376audio_device.append('ossaudiodev') 

377try: 

378 import ossaudiodev 

379 audio_modules['ossaudiodev'] = True 

380 audio_installed.append('ossaudiodev') 

381except ImportError: 

382 audio_modules['ossaudiodev'] = False 

383audio_required_deb_packages['ossaudiodev'] = ['osspd'] 

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

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

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

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

388 

389audio_device.append('winsound') 

390try: 

391 import winsound 

392 audio_modules['winsound'] = True 

393 audio_installed.append('winsound') 

394except ImportError: 

395 audio_modules['winsound'] = False 

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

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

398install the simpleaudio package in addition for better performance. 

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

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

401 

402 

403def installed_modules(func='all'): 

404 """Installed audio modules. 

405 

406 By default all installed modules are available. With 

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

408 the availability of installed modules can be controlled. 

409 

410 Parameters 

411 ---------- 

412 func: string 

413 'all': all installed audio modules. 

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

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

416  

417 Returns 

418 ------- 

419 mods: list of strings 

420 List of installed audio modules of the requested function. 

421 

422 See Also 

423 -------- 

424 available_modules() 

425 """ 

426 if func == 'fileio': 

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

428 elif func == 'device': 

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

430 else: 

431 return audio_installed 

432 

433 

434def available_modules(func='all'): 

435 """Installed and enabled audio modules. 

436 

437 By default all installed modules are available. With 

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

439 the availability of installed modules can be controlled. 

440 

441 Parameters 

442 ---------- 

443 func: string 

444 'all': all installed audio modules. 

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

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

447  

448 Returns 

449 ------- 

450 mods: list of strings 

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

452 of the requested function. 

453 """ 

454 if func == 'fileio': 

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

456 elif func == 'device': 

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

458 else: 

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

460 

461 

462def unavailable_modules(func='all'): 

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

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 not available, i.e. not installed and not enabled, audio modules 

476 of the requested function. 

477 """ 

478 if func == 'fileio': 

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

480 elif func == 'device': 

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

482 else: 

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

484 

485 

486def disable_module(module=None): 

487 """Disable an audio module. 

488 

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

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

491  

492 Parameters 

493 ---------- 

494 module: string or None 

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

496 If None disable all installed audio modules. 

497 

498 See Also 

499 -------- 

500 enable_module(), select_module(), available_modules(), list_modules() 

501 """ 

502 if module is None: 

503 for module in audio_installed: 

504 audio_modules[module] = False 

505 elif module in audio_modules: 

506 audio_modules[module] = False 

507 

508 

509def enable_module(module=None): 

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

511  

512 Parameters 

513 ---------- 

514 module: string or None 

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

516 If None enable all installed audio modules. 

517 

518 See Also 

519 -------- 

520 disable_module(), available_modules(), list_modules() 

521 """ 

522 if module is None: 

523 for module in audio_installed: 

524 audio_modules[module] = True 

525 elif module in audio_modules: 

526 audio_modules[module] = (module in audio_installed) 

527 

528 

529def select_module(module): 

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

531 

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

533  

534 Parameters 

535 ---------- 

536 module: string 

537 Name of the module to be selected. 

538 

539 Returns 

540 ------- 

541 selected: bool 

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

543 In this case the other modules are not disabled. 

544 

545 See Also 

546 -------- 

547 enable_module(), disable_module(), available_modules(), list_modules() 

548 """ 

549 if module not in audio_installed: 

550 return False 

551 for mod in audio_installed: 

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

553 return True 

554 

555 

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

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

558  

559 Modules that are not installed but are recommended are marked 

560 with an all uppercase "NOT installed". 

561 

562 Parameters 

563 ---------- 

564 module: string 

565 If 'all' list all modules. 

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

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

568 Otherwise list only the specified module. 

569 availability: bool 

570 Mark availability of each module by an asterisk. 

571 

572 See Also 

573 -------- 

574 installed_modules() 

575 missing_modules() 

576 missing_modules_instructions() 

577 """ 

578 def print_module(module, missing, print_type): 

579 audio_avail = '' 

580 if availability: 

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

582 audio_type = '' 

583 if print_type: 

584 if module in audio_fileio: 

585 audio_type += 'F' 

586 if module in audio_device: 

587 audio_type += 'D' 

588 if len(audio_type) > 0: 

589 audio_type = f' ({audio_type})' 

590 if module in audio_installed: 

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

592 elif module in missing: 

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

594 else: 

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

596 

597 missing = missing_modules() 

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

599 print_module(module, missing, True) 

600 else: 

601 print_type = (module == 'all') 

602 modules = sorted(audio_modules.keys()) 

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

604 for mod in audio_fileio: 

605 print_module(mod, missing, print_type) 

606 modules.remove(mod) 

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

608 for mod in audio_device: 

609 if mod in modules: 

610 print_module(mod, missing, print_type) 

611 modules.remove(mod) 

612 if module == 'all': 

613 for mod in modules: 

614 print_module(mod, missing, print_type) 

615 

616 

617def missing_modules(func='all'): 

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

619 

620 Parameters 

621 ---------- 

622 func: string 

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

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

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

626  

627 Returns 

628 ------- 

629 mods: list of strings 

630 List of missing audio modules of the requested function. 

631 """ 

632 mods = [] 

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

634 if 'soundfile' not in audio_installed and \ 

635 'wavefile' not in audio_installed: 

636 mods.append('soundfile') 

637 if 'audioread' not in audio_installed: 

638 mods.append('audioread') 

639 if 'pydub' not in audio_installed: 

640 mods.append('pydub') 

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

642 if 'pyaudio' not in audio_installed and \ 

643 'sounddevice' not in audio_installed: 

644 mods.append('sounddevice') 

645 return mods 

646 

647 

648def missing_modules_instructions(func='all'): 

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

650 

651 Parameters 

652 ---------- 

653 func: string 

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

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

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

657 """ 

658 mods = missing_modules(func) 

659 if len(mods) > 0 : 

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

661 for mod in mods: 

662 print() 

663 print(f'{mod}:') 

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

665 print(installation_instruction(mod)) 

666 else: 

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

668 

669 

670def installation_instruction(module): 

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

672 

673 Parameters 

674 ---------- 

675 module: string 

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

677  

678 Returns 

679 ------- 

680 msg: multi-line string 

681 Installation instruction for the requested module. 

682 """ 

683 install_package_deb = "sudo apt install" 

684 install_package_rpm = "dnf install" 

685 install_package_brew = "brew install" 

686 install_package = None 

687 package = None 

688 required_packages = None 

689 multiline = False 

690 instruction = None 

691 

692 install_pip_deb = "sudo pip install" 

693 install_pip_rpm = "pip install" 

694 install_pip_osx = "pip install" 

695 install_pip_win = "pip install" 

696 install_pip = install_pip_deb 

697 

698 install_conda = "conda install" 

699 

700 # check operating system: 

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

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

703 install_package = install_package_rpm 

704 install_pip = install_pip_rpm 

705 package = audio_rpm_packages.get(module, None) 

706 required_packages = audio_required_rpm_packages.get(module, None) 

707 else: 

708 install_package = install_package_deb 

709 package = audio_deb_packages.get(module, None) 

710 required_packages = audio_required_deb_packages.get(module, None) 

711 instruction = audio_instructions_linux.get(module, None) 

712 elif sys.platform == "darwin": 

713 install_package = install_package_brew 

714 install_pip = install_pip_osx 

715 package = audio_brew_packages.get(module, None) 

716 required_packages = audio_required_brew_packages.get(module, None) 

717 multiline = True 

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

719 install_package = '' 

720 install_pip = install_pip_win 

721 instruction = audio_instructions_windows.get(module, None) 

722 # check conda: 

723 conda = "CONDA_DEFAULT_ENV" in os.environ 

724 conda_package = audio_conda_packages.get(module, None) 

725 if conda: 

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

727 

728 pip_package = audio_pip_packages.get(module, None) 

729 

730 req_inst = None 

731 if required_packages is not None: 

732 if multiline: 

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

734 else: 

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

736 if pip_package is None and package is None: 

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

738 else: 

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

740 

741 pip_inst = None 

742 if pip_package is not None: 

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

744 

745 dist_inst = None 

746 if package is not None: 

747 if pip_inst is None: 

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

749 else: 

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

751 

752 conda_inst = None 

753 if conda and conda_package is not None: 

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

755 req_inst = pip_inst = dist_inst = instruction = None 

756 

757 info = audio_infos.get(module, None) 

758 

759 msg = '' 

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

761 if s is not None: 

762 if len(msg) > 0: 

763 msg += '\n\n' 

764 msg += s 

765 

766 return msg 

767 

768 

769def main(*args): 

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

771 

772 Run this module as a script 

773 ``` 

774 > python -m src.audioio.auidomodules 

775 ``` 

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

777 ```sh 

778 > audiomodules 

779 ``` 

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

781 how to install further audio packages. 

782 

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

784 ```sh 

785 > audiomodules --help 

786 ``` 

787 

788 Parameters 

789 ---------- 

790 args: list of strings 

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

792 """ 

793 if len(args) == 0: 

794 args = sys.argv[1:] 

795 if len(args) > 0: 

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

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

798 sys.exit(0) 

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

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

801 print('') 

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

803 print('') 

804 print('optional arguments:') 

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

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

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

808 print('') 

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

810 return 

811 

812 print('') 

813 if len(args) > 0 : 

814 mod = args[0] 

815 if mod in audio_modules: 

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

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

818 print(installation_instruction(mod)) 

819 print('') 

820 else: 

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

822 print('-'*41) 

823 print('') 

824 list_modules('all', False) 

825 print('') 

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

827 print('') 

828 missing_modules_instructions() 

829 print('') 

830 

831 

832if __name__ == "__main__": 

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