音声分析合成関連で使える便利な関数のメモ

# はじめに
音声変換をするときによく使うものの使い方をまとめた自分用メモです。
間違いなどありましたらご指摘いただけると喜びます。

実装や表示の仕方などは
こちらの[colab](https://colab.research.google.com/drive/10WQflIRe13rRx6XH5DqIylCpQWv08Ydr?usp=sharing)にまとめています。

以下のコード(Python)で全部インポートできます。
必要に応じでインポートしてね。

```py
import librosa
import librosa.display
import soundfile as sf
from nnmnkwii.util import example_audio_file, trim_zeros_frames
import matplotlib.pyplot as plt
import pyworld as pw
import pysptk
import pyreaper
import numpy as np
import IPython.display
```

# LibROSA
この子を使うと音声関連の基本的なことは全部できます！

## 音声の読み込み
以下のコードの場合wavに音声のnumpy形式の一次元配列で格納される
srには音源のサンプルレートが格納される(今回の場合は22050)
引数のsrを変更すると元の音源のサンプルレートに関係なく変更することが可能

```py
wav, sr = librosa.load('/file/no/path.wav', sr=22050)
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/492613/0025040b-0583-f080-5a4b-802969064375.png)


## スペクトログラムの作成
以下のコードでスペクトログラムが取得できます。

```py
spec_ = librosa.stft(wav)
spec = np.abs(spec_)
spec = librosa.amplitude_to_db(spec, ref=np.max)
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/492613/c625842b-bc7d-4c34-2b2b-3e5165e286ea.png)


## メルスペクトログラムの作成

```py
mlsp = librosa.feature.melspectrogram(y=wav, sr=sr)
mlsp = librosa.power_to_db(mlsp, ref=np.max)
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/492613/66d4c1f5-8532-31aa-9570-68090a327ddc.png)


## MFCCの作成

```py
mfccs = librosa.feature.mfcc(y=wav, sr=sr)
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/492613/b7d6788d-c85d-cb7b-09a8-aef964587d8b.png)


## それぞれの復元方法
復元の際に位相推定の手法である`griffinlim`を用いるのですがあまり精度はよくありません。
代替手法としてwavenetなどを用いる手法などがあります。

### スペクトログラム

`np.abs()`を用いていないなら以下の方法でいけます

```py
spec__to_wav = librosa.istft(spec_)
```

`np.abs()`を使った場合は位相推定をしないとなので以下で復元できます。

```py
spec_to_wav = librosa.db_to_amplitude(spec)
spec_to_wav = librosa.griffinlim(spec_to_wav)
```

### メルスペクトログラム

```py
mlsp_to_wav = librosa.db_to_amplitude(mlsp)
mlsp_to_wav = librosa.feature.inverse.mel_to_audio(mlsp_to_wav)
```

### MFCC(Mel Frequency Cepstral Coefficient)

```py
mfccs_to_wav = librosa.feature.inverse.mfcc_to_audio(mfccs)
```

## 音声の保存

```py
sf.write('./new_file.wav', wav, sr)
```

### librosa.output.write_wav について
最近のバージョンで動かなくなったみたいです。

もし人のコードを動かしていて`AttributeError: module 'librosa' has no attribute 'output'`と怒られた場合、おそらくバージョン問題なので、以下のコマンドでなんとかなると思います。

```bash
pip install librosa==0.7.2
pip install numba==0.48.0
```

# PyWORLD
音声分析合成システムWORLDのPython実装です。
UTAUなどにも使われているそうです。
音声合成や音声変換の時に非常に便利です！

Librosaで読み込んだ場合以下のようにnumpyの型を変換する必要があります。

```py
wav = wav.astype(np.float64)
```

## F0の推定
F0を推定する手法はふたつあります。

1. dio + stonemask: 高速で低精度な手法
2. harvest: 低速で高精度な手法

### dio + stonemask

おれは人間をやめるぞ！ジョジョーーッ！！


```py
_f0, t = pw.dio(wav, sr) 
f0 = pw.stonemask(wav, _f0, t, sr)
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/492613/ae34cf98-3809-4971-3656-101e46760569.png)

### harvest

```py
f0, t = pw.harvest(wav, sr)
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/492613/c5025482-e5a1-c628-dbc4-ec37ffdf1403.png)

## スペクトル包絡の推定

```py
sp = pw.cheaptrick(wav, f0, t, sr)
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/492613/2c029178-470e-cb17-3b08-a2e3912feadc.png)

## 非周期性指標の推定

```py
ap = pw.d4c(wav, f0, t, sr)
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/492613/2e12c6f5-7b98-3a6f-ae93-4c2ef710f191.png)

## まとめてF0, スペクトル包絡, 非周期性指標を推定

```py
f0, sp, ap = pw.wav2world(wav, sr)
```

## MCEPs(Mel Cepstral Coefficients)の推定

```py
mceps = pw.code_spectral_envelope(sp, sr, 24)
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/492613/226cc862-8c32-c813-8e60-5339c8b16814.png)

## MCEPsからスペクトル包絡の復元

```py
fftlen = pw.get_cheaptrick_fft_size(sr)
mceps_to_sp = pw.decode_spectral_envelope(mceps, sr, fftlen)
```

## WORLDから音声の復元

```py
world_to_wav = pw.synthesize(f0, sp, ap, sr)
```

# pyreaper
F0の推定などができます。
自分は有声区間などを調べるときに使ったりしています。
ライブラリ名がかっこいいです。

使う場合は型が`np.int16`じゃないといけないようです。

```py
path = pysptk.util.example_audio_file()
wav, sr = librosa.load(path, sr=22050)
wav = (wav*32767).astype(np.int16)
```

## 推定する

```py
pm_times, pm, f0_times, f0, corr = pyreaper.reaper(wav, sr)
```

### Pitch mark

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/492613/c4c0597f-fd50-fc50-d996-c5d6ca6391be.png)

### F0 contour

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/492613/eaca2634-701b-64b6-71ce-f6eaf7583e02.png)

### Correlations

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/492613/4d40b709-a1a7-0b10-922c-9a5525d627f8.png)


# 今後調査したいライブラリ
今回、調査したライブラリ以外も今後時間があったら調査して追記していこうと思います。

- nnmnkwii
    - https://r9y9.github.io/nnmnkwii/v0.0.1/design_jp.html
- WaveNet vocoder
    - https://github.com/r9y9/wavenet_vocoder
- inaSpeechSegmenter
    - https://github.com/ina-foss/inaSpeechSegmenter
- PyAudioAnalysis
    - https://github.com/tyiannak/pyAudioAnalysis
- PyAudio
    - https://people.csail.mit.edu/hubert/pyaudio/docs/

# さいごに
音声分析合成関連のライブラリはアニオタホイホイな関数名が多く、
書いていて楽しいです。


# 参考文献
[librosa — librosa 0.8.0 documentation](https://librosa.org/doc/latest/index.html)
[python报错-AttributeError: module ‘librosa‘ has no attribute ‘output‘](https://blog.csdn.net/zkw_1998/article/details/112015654)
[音声分析合成システムWORLD](http://www.kki.yamanashi.ac.jp/~mmorise/world/)
[Python-Wrapper-for-World-Vocoder](https://github.com/JeremyCCHsu/Python-Wrapper-for-World-Vocoder)
[REAPER: Robust Epoch And Pitch EstimatoR](https://github.com/google/REAPER)
[pyreaper](https://github.com/r9y9/pyreaper)