import pip

# required dependencies
pip.main(['install', 'numpy'])
pip.main(['install', 'scipy'])
pip.main(['install', 'theano'])
pip.main(['install', 'pyaudio'])
print('\nFinished installing required dependencies')

# dependencies for GUI
pip.main(['install', 'pyqt5'])
pip.main(['install', 'pyqtgraph'])
print('\nFinished installing GUI dependencies')

"""
Explanation: <!---
The MIT License (MIT)

Copyright (c) 2017 Sean UN Wood

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
--->

Real-time Speech Enhancement with GCC-NMF
Sean UN Wood, August 2017
In this iPython notebook, we present a real-time Python implementation of the GCC-NMF speech enhancement algorithm presented in:

Sean UN Wood and Jean Rouat, Real-time Speech Enhancement with GCC-NMF: Demonstration on the Raspberry Pi and NVIDIA Jetson, Interspeech 2017 Show and Tell Demonstrations.

that built on previous work:
 - Sean UN Wood and Jean Rouat, Real-time Speech Enhancement with GCC-NMF, Interspeech 2017.
This is essentially a real-time implementation of the Online Speech Enhancement notebook presented previously, with the addition of soft GCC-NMF mask generation.
Notebook Overview

Preliminary setup: Python dependencies
Real-time GCC-NMF: Graphical User Interface (GUI)
Real-time GCC-NMF: Command-line Interface (CLI)
Configuration parameters

1. Preliminary setup
Dependencies
In addition to numpy and scipy, a few additional dependencies are required:

Theano for its GPU acceleration and optimizing compiler.
PyAudio for real-time audio playback.

To run the graphical user interface, we also require:
1. PyQt Python bindings for the Qt application framework.
2. pyqtgraph scientific graphics and GUI library.
Installing dependencies
All dependencies can be installed with pip, either on the command line:
$ pip install numpy scipy theano pyaudio
$ pip install pyqt5 pyqtgraph
or programatically from within this notebook or a Python interpreter:
End of explanation
"""


import logging
logging.getLogger().setLevel(logging.INFO)

"""
Explanation: 2. Real-time GCC-NMF: with GUI
Preliminary imports for logging
End of explanation
"""


from gccNMF.realtime.runRealtimeGCCNMF import RealtimeGCCNMF
RealtimeGCCNMF()
print('Done!')

"""
Explanation: Running real-time GCC-NMF
The real-time GCC-NMF executable can be found at gccNMF/realtime/runRealtimeGCCNMF.py. At the root directory of this repo, we can start the program as follows:
$ python gccNMF/realtime/runRealtimeGCCNMF.py
We can also start it programatically:
End of explanation
"""


from gccNMF.realtime.runRealtimeGCCNMF import RealtimeGCCNMFNoGUI
RealtimeGCCNMFNoGUI()
print('Done!')

"""
Explanation: Startup may take a little while the first time it runs, as we pre-learn several NMF dictionaries of varying size. The dictionaries are saved to data/pretrainedW, so subsequent launches will be much quicker.
Once the window opens, click the Play button (or hit space) and you should see something like this:

The images roll with the input audio in waterfall-style. At the left, we see the input spectrogram on top, and the output spectrogram on the bottom. At the right, we have the GCC-PHAT angular spectrogram of the input on top (numTDOA x time), and the NMF mask on the bottom (numAtoms x time). In the center-bottom, we see the currently selected NMF dictionary (numAtom x frequency). Finally, at the center-top, we have the controls over the GCC-NMF masking function, dictionary size, number of coefficient inference updates per frame, as well as buttons to control playback, enable/disable enhancement, and toggle the info strings above the images.
2.1 Real-time localization
In the example above, you have full control over all masking function parameters including the estimated target location, i.e. via the Center slider in the GCC-NMF Masking Function panel. You can instead enable real-time localization by clicking the Enable Localization button and selecting a desired sliding window size for the GCC-PHAT localization. Smaller window sizes will track faster changes in source position but may switch to background noise during short pauses in the speech. Larger window sizes result in a more stable tracking for more slowly moving speakers.
We can use the -i flag to start GCC-NMF with an input example with a moving speaker:
$ python gccNMF/realtime/runRealtimeGCCNMF.py -i data/dev_A_1_2_3_4_mix.wav
Then, by clicking Enable Localization, you should see something like the screenshot below. The red trace in the GCC-PHAT Angular Spectrogram panel shows the history of the estimated source location. Also note that the Center parameter of the masking function is now disabled as it is controlled automatically by the online localization algorithm.

3. Real-time GCC-NMF: no GUI
Real-time GCC-NMF can also be run without the GUI, by passing the --no-gui as an argument on the command line:
$ python gccNMF/realtime/runRealtimeGCCNMF.py --no-gui
or programatically by instantiating the RealtimeGCCNMFNoGUI class instead of the RealtimeGCCNMF class we used above:
End of explanation
"""


