[ASR] Mask-based dereverb algorithm
State: closed | Pull request: yes
Labels: name: ASR

# What does this PR do ?

This PR adds a multichannel input, multichannel output mask-based dereverberation algorithm based on weighted prediction error (WPE).

**Collection**: ASR

# Changelog 
- New: Dereverberation algorithm implemented in `MaskBasedDereverbWPE`
- Added unit tests for handling of convolution matrices
- Input length is now optional for `AudioToSpectrogram`
- Updated relevant unit tests

# Usage

An example script with a test vector is attached to this PR.

## Example script

[pr_5693_example_script.zip](https://github.com/NVIDIA/NeMo/files/10281448/pr_5693_example_script.zip)


## Code example

The algorithm can be used as follows:
```python
import soundfile as sf
import torch

from nemo.collections.asr.modules.audio_modules import MaskBasedDereverbWPE
from nemo.collections.asr.modules.audio_preprocessing import AudioToSpectrogram, SpectrogramToAudio
from nemo.collections.asr.parts.preprocessing.segment import AudioSegment

# Parameters
fft_length = 512
hop_length = fft_length // 2
filter_length = 8
delay = 2
num_iterations = 3

# Load audio
sample_rate = 16000
x = AudioSegment.from_file(filename, target_sr=sample_rate).samples.T

# Add batch dimension, shape (B, C, T)
x = x[None, ...]

# Prepare analysis and synthesis transforms
stft = AudioToSpectrogram(fft_length=fft_length, hop_length=hop_length)
istft = SpectrogramToAudio(fft_length=fft_length, hop_length=hop_length)

# Analysis transform
X, _ = stft(input=torch.tensor(x))

# Prepare dereverb instance
dereverb = MaskBasedDereverbWPE(filter_length=filter_length, prediction_delay=delay, num_iterations=num_iterations)
# Processing
Y, _ = dereverb(input=X, mask=None)

# Synthesis transform: shape (B, C, T)
y, _ = istft(input=Y)

# Save audio
sf.write('output/dereverb_output.wav', y.cpu().numpy()[0, ...].T, sample_rate)
```

## Signal example

Below we show spectrograms of the input signal and the processed output signal. Signals are available in the attached example. Only the first channel is shown.

Input signal                         |  Output signal
:-------------------------:|:-------------------------:
![dereverb_input_ch0](https://user-images.githubusercontent.com/108555623/208999856-5dcc8f4c-219d-488e-a2f0-e75406194eb8.png)          |  ![dereverb_output_ch0](https://user-images.githubusercontent.com/108555623/208999901-bbf9329f-1ea6-4f45-909a-1c85479b9b4a.png)


# Before your PR is "Ready for review"
**Pre checks**:
- [x] Make sure you read and followed [Contributor guidelines](https://github.com/NVIDIA/NeMo/blob/main/CONTRIBUTING.md)
- [x] Did you write any new necessary tests?
- [ ] Did you add or update any necessary documentation?
- [ ] Does the PR affect components that are optional to install? (Ex: Numba, Pynini, Apex etc)
  - [ ] Reviewer: Does the PR have correct import guards for all optional libraries?
  
**PR Type**:
- [x] New Feature
- [ ] Bugfix
- [ ] Documentation

If you haven't finished some of the above items you can still open "Draft" PR.


## Who can review?

Anyone in the community is free to review the PR once the checks have passed. 
[Contributor guidelines](https://github.com/NVIDIA/NeMo/blob/main/CONTRIBUTING.md) contains specific people who can review PRs to various areas.

# Additional Information
* Related to # (issue)