音声合成ライブラリ WORLDとは森勢将雅が作成した音声分析合成システムである。 このシステムは音声から基本周波数やスペクトル包絡を簡単に抽出でき, それらの特徴量から音声を合成することができる。
本レポートでは録音した音声に対して音質変換を試行する。
まず, 音質変換を行う音声の準備として自分の音声の録音を行う。
#録音するための関数の定義
# 省略 by 小澤
下記のコードを実行すると録音が開始される。(注意:最初にマイクアクセスの許可が求められるので許可をする。)
録音が終了するとこのノートブックがあるディテクトリ下にwavファイルが保存される。
second = 3 #録音する秒数
file="hello_jp.wav" #録音を保存するファイル名
#録音の実行
print(f"start record {second} [sec]")
record(second, file) #録音
print("finished record")
start record 3 [sec]
finished record
録音した音声の波形を確認する。
import librosa
import librosa.display
wave_data, fs = librosa.load(file, sr=16000) #音声ファイルの読み込み
librosa.display.waveshow(wave_data, sr=fs) #波形の描画
Audio(wave_data, rate = fs)
<ipython-input-11-cbc3821a62c6>:4: UserWarning: PySoundFile failed. Trying audioread instead. wave_data, fs = librosa.load(file, sr=16000) #音声ファイルの読み込み /usr/local/lib/python3.10/dist-packages/librosa/core/audio.py:183: FutureWarning: librosa.core.audio.__audioread_load Deprecated as of librosa version 0.10.0. It will be removed in librosa version 1.0. y, sr_native = __audioread_load(path, offset, duration, dtype)
波形が確認できたため, 次にWORLDを用いて音質変換を行ってみる。
WORLDではC言語(C++)とMatlabが公開されているが, Pythonラッパ(PyWorld)があるため, 本レポートではそれを用いる。
#WORLDのPythonラッパのインストール
!pip install pyworld #pyworldのインストール
Collecting pyworld Downloading pyworld-0.3.4.tar.gz (251 kB) ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 252.0/252.0 kB 6.5 MB/s eta 0:00:00 Installing build dependencies ... done Getting requirements to build wheel ... done Preparing metadata (pyproject.toml) ... done Requirement already satisfied: numpy in /usr/local/lib/python3.10/dist-packages (from pyworld) (1.23.5) Requirement already satisfied: cython>=0.24 in /usr/local/lib/python3.10/dist-packages (from pyworld) (3.0.7) Building wheels for collected packages: pyworld Building wheel for pyworld (pyproject.toml) ... done Created wheel for pyworld: filename=pyworld-0.3.4-cp310-cp310-linux_x86_64.whl size=865277 sha256=68f6835f3b91459beaca605f6166a70f5cc919a5206c9a0daeb985461d1bcd59 Stored in directory: /root/.cache/pip/wheels/66/09/8a/a1d79b73d59756f66e9bfe55a199840efc7473adb76ddacdfd Successfully built pyworld Installing collected packages: pyworld Successfully installed pyworld-0.3.4
#特徴量の抽出
import pyworld as pw
wave_data = wave_data.astype(np.float64) #WORLDはfloat型を使用しているためfloat型にする
ff, time = pw.dio(wave_data, fs) #基本周波数抽出
f0 = pw.stonemask(wave_data, ff, time, fs) #基本周波数修正
sp = pw.cheaptrick(wave_data, ff, time, fs) #スペクトル包絡抽出
ap = pw.d4c(wave_data, ff, time, fs) #非周期性指標抽出
得られた特徴量から音声を合成を行い, 元の音声と合成した音声の波形の比較を行った。 その結果, 元の音声と合成した音声の波形がほぼ同じであるが, 合成した音声の方が振幅が若干大きいことわかった。 また, 合成した音声を確認してみると元の音声と変化がほぼ無いことがわかった。しかし, 元の音声よりも音声に入っている雑音が強調されたように聞こえる。 これは, 基本周波数やスペクトル包絡の抽出し, 音声合成する際の誤差によって引き起こされたものだと考えられる。
synthesis = pw.synthesize(f0, sp, ap, fs) #音声の合成
plt.subplot(211)
librosa.display.waveshow(wave_data, sr=fs) #元の音声の波形の描画
plt.title('Original')
plt.xlabel('Time (s)')
plt.ylabel('Amplitude')
plt.ylim([-0.8,0.8])
plt.show()
plt.subplot(212)
librosa.display.waveshow(synthesis, sr=fs) #合成した音声の波形の描画
plt.title('Synthesized')
plt.xlabel('Time (s)')
plt.ylabel('Amplitude')
plt.ylim([-0.8,0.8])
plt.show()
Audio(synthesis, rate=fs) #合成した音声の出力
音声の特徴量の抽出が行えたため, 以下の音質変換を試行した。
日本音響学会の音のなんでもコーナー Q and Aでは 「男性の基本周波数の平均値と標準偏差はそれぞれ125 Hz 及び20.5 Hz, 女性ではそれぞれ男性の約2倍に等しいことが分かっています。」$^{1)}$とある。 このことから, 元の音声の基本周波数を2倍にすれば, 女性のような音声へ音質変換ができると考えられる。 そのため, 元の音声の基本周波数を2倍にし, 音声を合成した。
#女性のような音声への音質変換
f0_female=f0*2 #元の音声の基本周波数を2倍
convert_female = pw.synthesize(f0_female, sp, ap, fs) #音声の合成
Audio(convert_female, rate=fs)
音質変換した音声を聞いたところ, 女性のような音声になっていることが確認できた。
基本周波数を確認したところ, 元の音声の基本周波数は125 Hz 程度になっており, 合成した音声はその2倍になっていることが確認できた。
plt.plot(f0,label="original")
plt.plot(f0_female,color="red",linestyle = "dashed",label="convert_female")
plt.legend(fontsize=10)
plt.xlabel('Time (frame)')
plt.ylabel('Frequency (Hz)')
plt.show()
また, スペクトログラムを確認したところ, 女性のような音声(右図)の方が高い周波数の成分の音量が強くなり, 低い周波数の成分の音量が小さくなっていることがわかった。よって, 基本周波数を2倍にすると女性のような音声に音質変換できることがわかった。
plt.figure(figsize=(13,5),tight_layout=True)
plt.subplot(121)
plt.specgram(synthesis, NFFT=256, Fs=fs, cmap='jet')
plt.title('Original')
plt.ylabel('Frequency (Hz)')
plt.xlabel('Time (s)')
plt.subplot(122)
plt.specgram(convert_female, NFFT=256, Fs=fs, cmap='jet')
plt.title('Female')
plt.ylabel('Frequency (Hz)')
plt.xlabel('Time (s)')
plt.show()
元の音声の抑揚をなくせばロボットのような音声に音質変換できると考えた。 音声の抑揚をなくすには音声の高さが一定, つまり基本周波数が一定となっていれば実現できると考えられる。 そのため, 基本周波数を一定にし, 音声を合成した。 なお, このときの基本周波数は男性の基本周波数の平均値125 Hzとした。
#ロボットのような音声への音質変換
f0_robot=np.zeros(len(f0))
for i in range(len(f0)):
f0_robot[i]=125
plt.plot(f0_robot)
plt.xlabel('Time (frame)')
plt.ylabel('Frequency (Hz)')
plt.show()
convert_robot = pw.synthesize(f0_robot, sp, ap, fs) #音声の合成
Audio(convert_robot, rate=fs)
音質変換した音声を聞いたところ, 抑揚がなくなりロボットのような音声が確認できた。
また, 3.3.1のように男性の音声の基本周波数を2倍にすると女性の音声の基本周波数になることからロボットのよう, かつ女性のような音声への音質変換も行った。その結果, ロボットのよう, かつ女性のような音声に音質変換できた。
#ロボットのようかつ女性のような音声への音質変換
for i in range(len(f0)):
f0_robot[i]*=2
plt.plot(f0_robot)
plt.xlabel('Time (frame)')
plt.ylabel('Frequency (Hz)')
plt.show()
convert_robot_female = pw.synthesize(f0_robot, sp, ap, fs) #音声の合成
Audio(convert_robot_female, rate=fs)
ロボットのような音声のスペクトログラムを確認したところ, 元の音声(左図)では黄色い部分があったりと音量がまばらな部分がある。しかし, ロボットのような音声ではまばらな部分が消え, 横軸と平行になっていることがわかる。よって, 基本周波数を一定にするとロボットのような音声へ音質変換できることがわかった。
plt.figure(figsize=(13,5),tight_layout=True)
plt.subplot(121)
plt.specgram(synthesis, NFFT=256, Fs=fs, cmap='jet')
plt.title('Original')
plt.ylabel('Frequency (Hz)')
plt.xlabel('Time (s)')
plt.subplot(122)
plt.specgram(convert_robot, NFFT=256, Fs=fs, cmap='jet')
plt.title('Robot')
plt.ylabel('Frequency (Hz)')
plt.xlabel('Time (s)')
plt.show()
ささやき声は声帯を振動させない音声(無声音)であり, その無声音のソースとして白色雑音が用いられる。 このことから, 基本周波数に白色雑音を組み合わせればささやき声のような音声への音質変換ができると考えた。 そのため白色雑音を作成し, 音声を合成した。
#白色雑音の作成
mean = 0.0 #白色雑音の平均値
std = 1.0 #白色雑音の分散
noise = np.random.normal(mean,std,fs)#白色雑音の作成
Audio(noise, rate=fs) #白色雑音の確認
# ささやき声への音質変換
f0_whisper=f0*noise[:len(f0)]
convert_whisper = pw.synthesize(f0_whisper, sp, ap, fs) #音声の合成
Audio(convert_whisper, rate=fs)
音質変換した音声を聞いたところ, ささやき声のような音声が確認できた。 ささやき声のような音声のスペクトログラム(右図)を確認したところ全体的に元の音声よりも音量が抑制されていることがわかる。また, 倍音構造が見られないこともわかる。これらのことから, 基本周波数に白色雑音を組み合わせればささやき声のような音声への音質変換ができることがわかった。
plt.figure(figsize=(13,5),tight_layout=True)
plt.subplot(121)
plt.specgram(synthesis, NFFT=256, Fs=fs, cmap='jet')
plt.title('Original')
plt.ylabel('Frequency (Hz)')
plt.xlabel('Time (s)')
plt.subplot(122)
plt.specgram(convert_whisper, NFFT=256, Fs=fs, cmap='jet')
plt.title('Whisper')
plt.ylabel('Frequency (Hz)')
plt.xlabel('Time (s)')
plt.show()
1) 松井知子, 音のなんでもコーナー Q and A | 日本音響学会, https://acoustics.jp/qanda/answer/50.html, 2023年2月3日アクセス
小澤賢司, 2022年, ディジタル音響信号処理入門-Pythonによる自主演習-, コロナ社
森勢将雅, Introduction|WORLD, http://www.isc.meiji.ac.jp/~mmorise/world/introductions.html, 2023年2月3日アクセス
森勢将雅, WORLDチュートリアル, http://www.kki.yamanashi.ac.jp/~mmorise/media/20170921/20170921.pdf, 2023年2月3日アクセス
ohtaman(株式会社ブレインパッド), 音声合成システム WORLD に触れてみる - Qiita, https://qiita.com/ohtaman/items/84426cee09c2ba4abc22, 2023年2月3日アクセス
Tomoki Hayashi, ESPnet2-ASR realtime demonstration, https://github.com/espnet/notebook/blob/master/espnet2_asr_realtime_demo.ipynb, 2023年2月3日アクセス
hayatowft, ノイズの時系列データの作り方 - Qiita, https://qiita.com/hayatowft/items/ecc16c08845af315c373, 2023年2月4日アクセス
Wikpedia, ささやき声 - Wikipedia, https://ja.wikipedia.org/wiki/%E3%81%95%E3%81%95%E3%82%84%E3%81%8D%E5%A3%B0, 2023年2月4日アクセス