Help us understand the problem. What is going on with this article?

音声分析合成システムWORLDなるものを使ってみる。

More than 1 year has passed since last update.
  • 注意

信号処理は専門外です。内容は正確でない場合があります。
開発環境はVisual C++ 2008 Express Editionです。

  • 概要

"音声分析合成システム"という名前の通りWORLDとは音声を分析、合成するライブラリです。入力音声からF0(声の高さ),非周期性指標(声のかすれ&子音),スペクトル包絡(声色)を得る関数とそれらの分解された情報から合成音声を得る関数を持ちます。

ボカロみたいに歌声を合成するソフトとしてUTAUというものが有りその中核で利用されています。

作者は山梨大学の森勢将雅先生。

  • 導入
  1. World-master.zip
    http://www.kki.yamanashi.ac.jp/~mmorise/world/
    からダウンロードします。今回使ったのはバージョン2.0.5のC++版。

  2. 解凍してmakefileまたはvisualstudio/win.slnからサンプルをコンパイルできるなら"サンプルで遊ぶ"へ飛ぶ。下図の私のように開発環境が古すぎたのでコンパイルできなかったひとは続きに進む01.JPG

  3. 新しく空のコンソールプロジェクトを作ってsourceフォルダとtestフォルダの中身をコピー。但しctest.cは無視。(恐らくtest.cppのc版なので要らない)
    プロジェクトのディレクトリ{
     audioio.h
     stdint.h
     audioio.cpp
     cheaptrick.cpp
     common.cpp
     d4c.cpp
     dio.cpp
     fft.cpp
     matlabfunctions.cpp
     stonemask.cpp
     synthesis.cpp
     test.cpp
     worldディレクトリ{
      cheaptrick.h
      common.h
      constantnumbers.h
      d4c.h
      dio.h
      fft.h
      macrodefinitions.h
      matlabfunctions.h
      stinemask.h
      synthesis.h
     }
    }
    みたいなファイル構成になっているはず
    これでコンパイルが通るならそれでいい
    私のようにstdint.hが足りんとエラーが出た人は続きを読む。

  4. http://www.vector.co.jp/soft/win95/prog/se432866.html
    からstdint-20070624.zipをダウンロードしてstdint.hとxstdint.hをプロジェクトのディレクトリに追加。これで私の場合はコンパイルが通った。

  • サンプルで遊ぶ

出てきたexe(私の場合はWORLD_0205.exe)で遊んでみる
入力wav名、出力wav名、スペクトルの伸縮率、基本周波数の伸縮率を引数にとるようだ。コマンドプロンプトからexeの周りに変換したいwavファイル(中に入っていたvaiueo2d.wavをそのまま使った)を持ってきて。
コマンドプロンプトから

cd C:\Documents and Set...(exeのフォルダ)
WORLD_0205.exe vaiueo2d.wav out.wav 2.0 1.3

と入力すると。vaiueo2d.wavのイケボがout.wavにボーイッシュな娘の声らしき何かに変換されていることが分かる。
vaiueo2d.wav
https://drive.google.com/file/d/0B8PHV9xzgpWdQTJUQ3g1UlR3N3c/preview

out.wav
https://drive.google.com/file/d/0B8PHV9xzgpWdZGVhem5rcklodVk/preview

  • 関数の概要

このライブラリ。解説が入っていない。
doc\readme_JP.txtに

使い方については,test.cppを参考にしてください.
(中略)
基本的な考え方:
音声は,音高と音色により表現できるといわれます.
最新版では,音声をF0,非周期性指標,スペクトル包絡で表現します.
これは,Vocoderと同一の考え方です.

(1) Dio() により音声の基本周波数を推定
(1-1) 必要に応じてStoneMask() により基本周波数を補正
(2) CheapTrick() により音声のスペクトル包絡を推定
(3) D4C() により音声の非周期性指標を推定
(4) 必要に応じて音高や音色の制御
(5) Synthesis() により音声を合成

とだけ書いてある。信号処理に明るくないので心配だが自分なりに解釈してみる

audioio.cpp、audioio.h、test.cppがサンプル部分、それ以外がライブラリである。

ライブラリの中にも色々関数があるが

F0,非周期性指標,スペクトル包絡 ← 音声信号

に各々Dio&StoneMask、D4C、CheapTrickを使い。

F0,非周期性指標,スペクトル包絡 → 音声信号

にSynthesisを使う

と覚えていれば良さそう。残りはハンバーガーにおけるレタスのような関数。

また解析関数や合成関数ではF0,非周期性指標,スペクトル包絡は一定の時間間隔毎に管理する。デフォルトでは5ミリ秒毎になっていて。その一つ一つをフレームと呼ぶらしい。

それぞれの関数の解説
//-----------------------------------------------------------------------------
// DIO 基本周波数を推定する
// 入力:
//   x          : 入力波形
//   x_length   : 入力波形の長さ
//   fs         : 標本化周波数(Hz)
//   option     : DIO詳細構造体
// 出力
//   time_axis  : フレームの時間的位置(sec)
//   f0         : フレームの基本周波数(Hz)
//
//optionはInitializeDioOption()で初期化してから必要なところを弄って渡す。
//f0_floor、f0_ceilが基本周波数の下限上限[Hz]。
//frame_periodがフレームの間隔[msec]
//
//time_axisとf0はGetSamplesForDIO()でフレーム数を計算できるのでその分だけ確保。
//time_axisとf0は後に多用するのでこの関数が解析を先行するようだ。
//-----------------------------------------------------------------------------
void Dio(const double *x, int x_length, int fs, const DioOption *option,
  double *time_axis, double *f0);
//-----------------------------------------------------------------------------
// D4C() 非周期性指標を推定する。
// 入力:
//   x            : 入力波形
//   x_length     : 入力波形の長さ
//   fs           : 標本化周波数
//   time_axis    : フレームの時間的位置[sec]
//   f0           : フレームの基本周波数[hz]
//   f0_length    : フレームの数
//   fft_size     : 高速フーリエ変換で利用するサイズ。
// 出力
//   aperiodicity : 非周期性指標
//
//fft_sizeはGetFFTSizeForCheapTrick()で得たものを使用する。
//
//aperiodicityは多次元配列[フレーム×周波数]。
//aperiodicity = new double *[f0_length];
//for(int i=0;i<f0_length;++i)aperiodicity[i]=newdouble[fft_size/2 + 1];
//のように確保する。fft_size/2+1というのは位相情報を切り捨てていることを意味していると思われる。
//またtest.cpp内でaperiodicity[n]を内挿法で弄っている様子なので。0番目の要素は適切に外挿してくれているのだろう。
//-----------------------------------------------------------------------------
void D4C(const double *x, int x_length, int fs, const double *time_axis,
  const double *f0, int f0_length, int fft_size, const D4COption *option,
  double **aperiodicity);

//-----------------------------------------------------------------------------
// CheapTrick() スペクトル包絡を推定する
// 入力:
//   x            : 入力波形
//   x_length     : 入力波形の長さ
//   fs           : 標本化周波数
//   time_axis    : フレームの時間的位置[sec]
//   f0           : フレームの基本周波数[hz]
//   f0_length    : フレームの数
//   option       : cheaptrick詳細構造体
// 出力
//   spectrogram  : スペクトル包絡
//
//spectrogramはaperiodicityと同じように扱えばいい。
//optionはInitializeCheapTrickOptionで初期化してから弄る。
//option->f0_floorは声の基本周波数の下限
//-----------------------------------------------------------------------------
void CheapTrick(const double *x, int x_length, int fs, const double *time_axis,
  const double *f0, int f0_length, const CheapTrickOption *option,
  double **spectrogram);
//-----------------------------------------------------------------------------
// StoneMask() Dioの推定結果を修正するらしい。無くても何とかなりそうだが取り合えず使っとくのが吉。
// 入力:
//   x                      : 入力波形
//   x_length               : 入力波形の長さ
//   fs                     : 標本化周波数
//   time_axis              : フレームの時間的位置[sec]
//   f0                     : フレームの基本周波数[hz]
//   f0_length              : フレームの数
// 出力
//   refined_f0             : フレームの修正基本周波数[hz]
//-----------------------------------------------------------------------------
void StoneMask(const double *x, int x_length, int fs, const double *time_axis,
  const double *f0, int f0_length, double *refined_f0);
//-----------------------------------------------------------------------------
// Synthesis() で合成
// 入力:
//   f0                   : フレームの基本周波数[hz]
//   f0_length            : フレームの数
//   spectrogram          : スペクトル包絡 by CheapTrick
//   fft_size             : FFT長 by GetFFTSizeForCheapTrick
//   aperiodicity         : 非周期性指標 by D4C
//   frame_period         : フレームの時間的間隔[msec] by DIO
//   fs                   : 標本化周波数
//   y_length             : 合成波形の長さ
//=int((枠の数-1)*frame_period/1000.0*fs)+1(切り上げ)
// 出力
//   y                    : 合成波形
//-----------------------------------------------------------------------------
void Synthesis(const double *f0, int f0_length, double **const spectrogram,
    double **const aperiodicity, int fft_size, double frame_period, int fs,
    int y_length, double *y);

WORLDをdll化してjnaでjavaに組み込んで使う予定。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした