STRAIGHT Library

はじめに

音声分析変換合成法STRAIGHTをC・C++言語から使えるようにしたライブラリです。 MATLABによるSTRAIGHTの実装を元に、C言語に移植し、ライブラリ化したものです。 STRAIGHTに詳しくない人でも音声分析変換が容易に行え、かつ、STRAIGHTに詳しい人 は、きめ細かいパラメータの制御ができるようなAPIの提供を目指しています。 なお、STRAIGHTライブラリという名前のものは、我々グループの内部にも色々な ものがあるため、公開用のSTRAIGHTライブラリをSTRAIGHTライブラリ(Official版)と 呼ぶことにします。

STRAIGHTについて

STRAIGHTについて、簡単に説明します。 STRAIGHT(Speech Transformation and Representation using Adaptive Interpolation of weiGHTed spectrogram)は、極めて高品質な音声分析合成システムです。 音声分析合成は、これまで品質が高くないと言われてきましたが、 STRAIGHTは、基本周波数やスペクトル包絡が極めて精密に求められているなどの 点で既存の音声分析合成と異なっており、高い品質が得られます。

STRAIGHTの処理は、(1)声の高さなど、声帯音源に関する情報を抽出する部分と、 (2)音韻性や声質に大きく寄与するスペクトルの時間系列(スペクトログラム)を抽出する部分、 (3)これらの部分の出力から音声を合成する部分の3つの部分に大きく分けることができます。 ここでは、(1)を音源分析部、(2)をスペクトログラム分析部、(3)を合成部と呼ぶことにし、 これらの処理により得られるパラメタをSTRAIGHTパラメタと呼ぶことにします。 また、STRAIGHT処理を行う部分のことをSTRAIGHTエンジンなどと呼ぶことにします。

プログラム作成方法

簡単なプログラム

ここでは、STRAIGHTライブラリの基本APIを用いて、簡単な音声分析合成のプログラムを作成する手順について説明します。 分析合成を行うまでの一連の手順は次のようになります。

  1. STRAIGHTエンジン全体の設定を行うための構造体StraightConfigを、straightInitConfigを呼び出して初期化
  2. 必要に応じて構造体StraightConfigの各メンバの値を設定
  3. straightInitializeを呼び出し、STRAIGHTエンジンを初期化
  4. 音声ファイルの読み込み(STRAIGHTライブラリでも簡単な読み込み関数straightReadAudioFileを提供しています)
  5. straightSourceInitializeを呼び出し、STRAIGHT音源分析エンジンを初期化
  6. straightSourceComputeを呼び出し、音源分析を実行
  7. straightSpecgramInitializeを呼び出し、STRAIGHTスペクトログラム分析エンジンを初期化
  8. straightSpecgramComputeを呼び出し、スペクトログラム分析を実行
  9. straightSynthInitializeを呼び出し、STRAIGHT合成エンジンを初期化
  10. straightSynthComputeを呼び出し、合成を実行
  11. 合成された音声を音声ファイルとして書き出し (STRAIGHTライブラリでも簡単な書き込み関数straightWriteSynthAudioFileを提供しています)
  12. straightSourceDestroy、straightSpecgramDestroy、straightSynthDestroyを呼び出し、それぞれのエンジンを解放
  13. straightDestroyを呼び出し、STRAIGHTエンジンを解放

この一連の手順に従って作成したプログラムは以下のようになります。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <straight/straight.h>

char inputFileName[256] = "";
char outputFileName[256] = "";

char outputPluginName[256] = "output_wav";

int main(int argc, char *argv[])
{
    StraightConfig config;  /* STRAIGHTエンジン全体の設定用構造体 */
    Straight straight;
    StraightSource source;
    StraightSpecgram specgram;
    StraightSynth synth;

    if (argc < 3) {
        fprintf(stderr, "simple <input file> <output file>\n");
        exit(1);
    }
    
    strcpy(inputFileName, argv[1]);
    strcpy(outputFileName, argv[2]);

    /* STRAIGHTエンジン設定用構造体の初期化 */
    straightInitConfig(&config);

    /* デフォルトのサンプリング周波数を指定 */
    config.samplingFrequency = 16000.0;

    /* STRAIGHTエンジン初期化 */
    if ((straight = straightInitialize(&config)) != NULL) {
        /* 音声ファイル読み込み */
        if (straightReadAudioFile(straight, inputFileName, NULL) == ST_FALSE) {
            fprintf(stderr, "Error: Cannot open file: %s\n", inputFileName);
        } else {
            fprintf(stderr, "Input file: %s\n", inputFileName);
            
            /* 音源分析エンジン初期化 */
            source = straightSourceInitialize(straight, NULL);

            /* 音源分析実行 */
            straightSourceCompute(straight, source, NULL, 0);

            /* スペクトログラム分析エンジン初期化 */
            specgram = straightSpecgramInitialize(straight, NULL);

            /* スペクトログラム分析実行 */
            straightSpecgramCompute(straight, source, specgram, NULL, 0);

            /* 合成エンジン初期化 */
            synth = straightSynthInitialize(straight, NULL);

            /* 合成の実行 
             * 最後の3つの引数の値を変えることにより,基本周波数・周波数軸・時間軸の変更が可能 */
            if (straightSynthCompute(straight, source, specgram, synth, 1.0, 1.0, 1.0) == ST_TRUE) {
                /* 合成音を音声ファイルとして書き込み */
                if (straightWriteSynthAudioFile(straight, synth,
                                                outputFileName, outputPluginName, 16) == ST_TRUE) {
                    fprintf(stderr, "Output file: %s\n", outputFileName);
                } else {
                    fprintf(stderr, "Error: Cannot open file: %s\n", outputFileName);
                }
            }
    
            /* 各エンジン解放 */
            straightSourceDestroy(source);
            straightSpecgramDestroy(specgram);
            straightSynthDestroy(synth);
        }
        /* STRAIGHTエンジン解放 */
        straightDestroy(straight);
    } else {
        fprintf(stderr, "Error: Cannot initialize STRAIGHT engine\n");
    }

    return 0;
}

コールバック有りの場合

上で説明したプログラムでは、分析を行っている間は、関数から処理は返ってこないため、 ユーザからは処理が止まっているように見えます。 例えば、STRAIGHTライブラリでGUIを持つアプリケーションを作成した場合、分析中は 途中経過が全く表示されず、アプリケーションが応答しなくなってしまうことになります。

このような問題を解決する1つの方法は、STRAIGHTライブラリが用意しているコールバック関数を使用 することです。 コールバック関数を予め定義し、STRAIGHTエンジンに登録しておくと、 必要な処理の最中や処理の後にコールバック関数が呼ばれ、途中経過などをユーザに 見せることができるようになります。

以下のプログラムでは、コールバック関数により、分析や合成処理が何%進んでいるかを表示しています。 上のプログラムとの違いは、callbackFuncという名前のコールバック関数が定義されている点と、そのコールバック関数をstraightSetCallbackFuncを呼んで登録している点です。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <straight/straight.h>

char inputFileName[256] = "";
char outputFileName[256] = "";

char outputPluginName[256] = "output_wav";

static stBool callbackFunc(Straight straight, stCallbackType callbackType,
                           void *callbackData, void *userData)
{
    int percent;
    
    if (callbackType == STRAIGHT_F0_PERCENTAGE_CALLBACK) {
        percent = (int)callbackData;
        fprintf(stderr, "STRAIGHT F0: %d %%\r", percent);
        if (percent >= 100) {
            fprintf(stderr, "\n");
        }
    } else if (callbackType == STRAIGHT_AP_PERCENTAGE_CALLBACK) {
        percent = (int)callbackData;
        fprintf(stderr, "STRAIGHT AP: %d %%\r", percent);
        if (percent >= 100) {
            fprintf(stderr, "\n");
        }
    } else if (callbackType == STRAIGHT_SPECGRAM_PERCENTAGE_CALLBACK) {
        percent = (int)callbackData;
        fprintf(stderr, "STRAIGHT spectrogram: %d %%\r", percent);
        if (percent >= 100) {
            fprintf(stderr, "\n");
        }
    } else if (callbackType == STRAIGHT_SYNTH_PERCENTAGE_CALLBACK) {
        percent = (int)callbackData;
        fprintf(stderr, "STRAIGHT synthesis: %d %%\r", percent);
        if (percent >= 100) {
            fprintf(stderr, "\n");
        }
    }

    return ST_TRUE;
}

int main(int argc, char *argv[])
{
    StraightConfig config;
    Straight straight;
    StraightSource source;
    StraightSpecgram specgram;
    StraightSynth synth;

    if (argc < 3) {
        fprintf(stderr, "simpleCB <input file> <output file>\n");
        exit(1);
    }
    
    strcpy(inputFileName, argv[1]);
    strcpy(outputFileName, argv[2]);

    straightInitConfig(&config);
    config.samplingFrequency = 16000.0;

    if ((straight = straightInitialize(&config)) != NULL) {
        if (straightReadAudioFile(straight, inputFileName, NULL) == ST_FALSE) {
            fprintf(stderr, "Error: Cannot open file: %s\n", inputFileName);
        } else {
            fprintf(stderr, "Input file: %s\n", inputFileName);
            
            straightSetCallbackFunc(straight, STRAIGHT_PERCENTAGE_CALLBACK, callbackFunc, NULL);

            source = straightSourceInitialize(straight, NULL);
            straightSourceCompute(straight, source, NULL, 0);

            specgram = straightSpecgramInitialize(straight, NULL);
            straightSpecgramCompute(straight, source, specgram, NULL, 0);

            synth = straightSynthInitialize(straight, NULL);
            if (straightSynthCompute(straight, source, specgram, synth, 1.0, 1.0, 1.0) == ST_TRUE) {
                if (straightWriteSynthAudioFile(straight, synth,
                                                outputFileName, outputPluginName, 16) == ST_TRUE) {
                    fprintf(stderr, "Output file: %s\n", outputFileName);
                } else {
                    fprintf(stderr, "Error: Cannot open file: %s\n", outputFileName);
                }
            }
    
            straightSourceDestroy(source);
            straightSpecgramDestroy(specgram);
            straightSynthDestroy(synth);
        }
        straightDestroy(straight);
    } else {
        fprintf(stderr, "Error: Cannot initialize STRAIGHT engine\n");
    }

    return 0;
}

コールバック関数callbackFuncは、第2引数のcallbackTypeに応じて処理内容を変化させています。 この引数は、コールバック関数がどのような状況で呼ばれたかを 示すもので、例えば、この引数がSTRAIGHT_SPECGRAM_PERCENTAGE_CALLBACKという値であれば、 スペクトログラムの分析途中であることを示します。 第3引数callbackDataには、コールバック関数が呼ばれた状況に応じたデータが入っています。 ここで使われている〜PERCENTAGE_CALLBACKの場合は、callbackDataは、 int型で、その処理が何%終了したかを表す量が入っています。 第4引数userDataには、プログラマーがstraightSetCallbackFuncの第4引数で指定した データが入ります。このプログラムの場合はNULLになります。

ライセンス

ライセンスは未定です。


Last modified: "2008-12-17 19:35:04 hideki"