なんとなくポータブルで、スマホとかでもそこそこ動くような時間領域の音声信号処理ライブラリが欲しかった(音声信号処理というより普通のDSPだけど)ので、4月の頭に少しだけ無の時間があったので書いた。最近ホットな声質変換ではない普通のボイスチェンジャーとか。vocoderをやらずに波形の処理だけでやるピッチシフタとかの勉強もしたかった。
https://github.com/shunsukeaihara/ssp/
Header OnlyのC++のtemplate libraryになっていて、言語機能も新しい物全然使ってないので適当にブリッジを書けばいろいろ使えるはずだけれどドキュメントを整備する気はない。サンプルを見て感じてもらいたい。久しぶりのC++なので微妙なところはいろいろある。
https://github.com/shunsukeaihara/ssp/tree/master/samples
昔から雑に使えるボイチェンが欲しいなと思っていたこともあり、去年arxivに割とアルゴリズム的に安定してそうなOverlap and Add系の論文が投稿されていたので適当にそれも実装している。アルゴリズムの詳細は述べないがもともとTD-PSOLAと違ってtime stretchingが主眼となっているものなのでピッチとフォルマントの変換を独立に処理できないが、pitch mark(epoch mark)は取得できているのでやれば出来るはず。
他、音質調整の為以下の簡単なエフェクターを実装している。
- Noise Gate
- Peak Limitter
- Compressor
- Distortion
- Delay
- Biquad Filter
- Butterworth Filter
resamplerも書いているけれど、時間領域の手抜き処理なのでちゃんとしたfftベースのFractional Resamplerを持ってきたほうが良い。
ボイスチェンジャーについて
ピッチマークの抽出は零周波数レゾネータを用いて行っている。基本的にローパスフィルタ掛けて窓平均を取るもので、レゾネータを掛けた波形の正の零クロス点を基本周期の開始点として抽出する。DIOみたいにフィルタバンクは使っていないので軽い処理になる。
ピッチマークを処理する時の窓幅についてはパラメータにロバストだと書かれていたけれど、結構音声によって異なる(データに使っている女性声優の声が高いのか零周波数レゾネータベースのEpoch検出の論文のものより結構短い窓幅での処理が必要になる。)のと、判定ミスが残っている。なにか前処理を掛けたほうが良いかもしれない。2chに入っているのがEpoch Markで、過剰に短くepochが判定されている物が散見される。
あとは基本周期に同期してOverlap and Addをする。
簡易ボイスチェンジャーのサンプルは以下の通り。音声データは声優統計のデータを使っている(https://voice-statistics.github.io/#dataset)
サンプルコードにおいてあるやつを使って適当に生成
sox tsuchiya_normal_001.wav -t raw — | samples/bin/pitchshifter_sample |sox -r 48000 -b 16 -c 1-e signed -t raw — out.wav
終わりに
勉強として時間領域のOverlap and Addを実装してみてだいぶこのあたりの処理の勘所はつかめた感じはある。イケてるRing buffer作って簡単にストリームで処理するぜって考えてたけど久々のC++だったのも相まって結構いけていないインターフェイスになっているし、高速化周りも全然やっていないので実用には少し遠い感じはある。音質もまだ改善の余地はあるし。
次はPhase Vocoder周りを勉強しつつ、respeakerを買ってみたのでBeamformerのライブラリを整備していく予定。