Cadenciiマニュアル　応用

ここではある程度、把握している方に更に良いCadenciiの使用方法を紹介します。

■プロパティウィンドウにての数式入力
プロパティウィンドウの「クロック」「小節」「拍」「Tick」「長さ」の項目に、
現在の値に一定の値を加減乗除できるようになっています。

まず、1個の音符の位置を480clockずらす例を示します。
音符を選択すると、現在の音符の位置（クロック=7680）がプロパティウィンドウに表示されます。
クロック=7680の後ろに＋480と入力し、Enterキーを押すと、「7680+480」の値が計算され、音符が後ろに移動します。
複数の音符についても、同様の操作が可能です。複数の音符を選択すると、「クロック」の値が違うのでプロパティウィンドウは空白になります。 
構わずに「＋480」と入力して、Enterキーを押すと、それぞれの音符の「クロック」値に+480が加算され、複数の音符がまとめて移動します。 
ここでは足し算の例しか載せませんでしたが、加減乗除いずれも可能です。 
また、入力した文字列に"x"を含んだ数式を入力すると、xに現在の値が代入されて評価されます。 
たとえば、最初の例だと「7680+480」と入力する場合と「x+480」と入力する場合の結果は同じになります。 

■UTAU用のプラグインを使用するには
UTAU用のプラグインを使うには，まず，UTAU用プラグインとCadenciiの間を取り持つスクリプトを作成（インストール）する必要があります。
「歌詞を連続音にする」プラグインを例に，インストール手順を説明します。

まず、 「スクリプト」メニューの「UTAU用プラグインをインストール」を選びます。次にダイアログが出てきます。 
次に，インストールしたいプラグインの「plugin.txt」の場所を指定します．ダイアログの「追加」ボタンを押して，ファイル選択ダイアログで
plugin.txtを選択してください
選択できたら，リストにプラグインの名前と，「plugin.txt」へのパスが追加されていると思います。
「了解」ボタンを押すとダイアログが閉じ，インストールが行われます。

メイン画面に戻って「スクリプト」メニューを選択すると，インストールしたプラグインの名前が追加されます。
以上でインストールは終わりです。次は使い方です。
まず，現在のトラックがUTAUモードになっているかを確認します。（「トラック」メニュー→「歌声合成エンジン」→「UTAU」） 
UTAUの音源がちゃんと登録されているか確認します。（「設定」メニュー→「プリファレンス」，出てくるダイアログの「UTAU音源」タブ）

次に、プラグインで編集したい音符を範囲選択し、「スクリプト」メニューの中から，使いたいプラグインを選んで起動すれば大丈夫です。

■コントロールカーブのデータを数値入力する。
ポインターツールで，データ点をダブルクリックすると数値入力用のダイアログが出ます。
数値を入力して「適用」ボタンを押すと反映されます。

※上にあるボタン「<10」「<5」「<」は，それぞれ10個，5個，1個左隣のデータ点を選択しなおします。「>」「5>」「10>」は右隣のデータ点を選択しなおします。
「undo」「redo」ボタンは，メインウィンドウの「元に戻す」「やり直し」と同じ効果があります。

■VOCALOID1のSynthesize Engine 1.0と1.1を同時に使う方法。
※Windows VistaまたはWindows 7においてSynthesize Engine 1.0と1.1を同時に使用するためには，ユーザーアカウント制御(UAC)を無効にする必要があります． 

「設定」メニュー→「プリファレンス」とたどり，設定ダイアログを出す。
「シンセサイザー」タブを選択，「合成DLLの利用」にある「セカンダリVOCALOID1 DLLを読み込む」にチェックを入れる。
その下にある「VOCALOID1 [1.0]」と「VOCALOID1 [1.1]」の両方にチェックが入っているのを確認する。
「了解」ボタンを押す，Cadenciiを再起動する。

以上でSynthesize Engine 1.0と1.1の両方を使えるようになります。ただし，古いVOCALOID1のみがインストールされている場合，
1.1がそもそも存在しないので当然ながら両方使うのは不可能です。

・補足
•デフォルトでは，どちらか片方のSynthesize Engineのみが読み込まれます．読み込まれるのはVOCALOID1 Editorで設定したものになります。
•XVSQファイルには，1.0と1.1のどちらが指定されたかが保存されます．具体的には，<VsqTrack>要素の直下にある<Tag>要素内に，
「org.kbinani.cadencii.RendererKind:VOCALOID1_100」等と記録されます。
•XVSQと同時出力されるVSQファイルには，1.0と1.1のどちらが指定されたかは保存されません。
•2個のSynthesize Engineを読み込む際の仕組みについては，「VOCALOID1のSynthesize Engine 1.0と1.1の同時起動」をご覧ください。

■音が出ない／レンダリングがうまくいかない 
VOCALOID1/2のデモ版を使用している 
デモ版では使えないようにしてあります．残念ながら解決策はありません．
 
Windowsのセキュリティ設定により，プラグインのロード／外部の実行ファイルの起動が制限されている． 
Windows Vista，Windows 7では，管理者権限でCadenciiを実行するようにしてください．
 
一時ディレクトリの空き容量がほぼ0になっている 
一時ディレクトリの空き容量が枯渇していると，特に前触れも無く音が出なくなります．空き容量を確保してから再度実行してみてください． 
｛Cadenciiのインストールディレクトリ｝￥PlaySound.dllが存在しない 
｛Cadenciiのインストールディレクトリ｝￥plugins￥以下のdllが存在しない 
｛Cadenciiのインストールディレクトリ｝￥vConnect.exeが存在しない 
ファイルが存在しているかどうかを確認してください．ファイルが無かった場合は，Cadenciiを再インストールしてください． 

Visual C++ ライブラリDLLがインストールされていない 
Straight x UTAUの機能を使用するには，Visual C++ライブラリDLLがインストールされている必要があります。
入手先：http://www.microsoft.com/downloads/details.aspx?familyid=9b2da534-3e03-4391-8a4d-074b9f2bc1bf&displaylang=ja

ローマ字の歌詞のまま音を鳴らそうとしている 
UTAUモードとStraight x UTAUモードでは、ローマ字の歌詞のみでは音抜けが発生します
（エイリアス設定によりローマ字などのアルファベットにも音がマップされている場合は別として）。
たとえば「あ」と歌わせようとして「a」と入力した場合、実際に音源から検索されるのは「a.wav」なので、これが無い場合音抜けが発生することになります。

■スクリプトの書き方 
構文と必要な定義
 構文はC#と全く同じです。
http://www9.atwiki.jp/boare/pages/32.html　←にあるようにクラスの定義を記述してください。クラスには関数のうちどれか一つを、必要に応じて実装してください。

•public static bool Edit( Boare.Lib.Vsq.VsqFile vsq );
•public static bool Edit( Boare.Cadencii.VsqFileEx vsq );
•public static ScriptReturnStatus Edit( Boare.Lib.Vsq.VsqFile vsq );
•public static ScriptReturnStatus Edit( Boare.Cadencii.VsqFileEx vsq );

boolが戻り値のものは、スクリプトの実行が成功したときtrueを、そうでないときfalseを返すように実装してください。 
ScriptReturnStatusが戻り値のものは、 

•スクリプトの実行が成功し、編集が行われたときScriptReturnStatus.EDITEDを、
•スクリプトの実行が成功したが、編集は行われなかったときScriptReturnStatus.NOT_EDITEDを、
•スクリプトの実行が失敗したか、または中断されたときScriptReturnStatus.ERROR
をそれぞれ返すように実装してください。
 
また、using句は次のリストのものをスクリプトの先頭に含めることができます。 
•using System;
•using System.IO;
•using Boare.Lib.Vsq;
•using Boare.Cadencii;
•using bocoree;
•using Boare.Lib.Media;
•using Boare.Lib.AppUtil;
•using System.Windows.Forms;
•using System.Collections.Generic;
•using System.Drawing;
•using System.Text;
•using System.Xml.Serialization

スクリプトの配置
 Cadenciiの本体が保存されているディレクトリに「script」というディレクトリを作成し、その中にスクリプトを保存してください。拡張子は.txtまたは.csが有効です。
エンコーディングについては、2バイト文字を含む場合UTF-8（BOMの有無は問わない）で保存しないと文字化けします。 

■STRAIGHT x UTAUの機能を使う場合。

STRAIGHT音声合成用の解析ファイルを作成する。
STRAIGHT音声合成を行うには，あらかじめ音源の音声ファイルを解析する必要があります。解析結果は，各音源フォルダ直下の「analyzed」というフォルダに保存されます。
拡張子は.stfです。同梱のユーティリティ，「EditOtoIni.exe」を使ってSTFファイルを作成してください。

・UTAU音源設定ユーティリティ
UTAU音源用の設定ファイルoto.iniを編集し、STRAIGHT用解析ファイルの管理を行うユーティリティです。 
使用するには、Cadencii本体の「設定」→「UTAU音源」メニューをたどるか、直接「EditOtoIni.exe」をダブルクリックして起動します。 

画面は3つのパートに分かれています。それぞれ、左上が「oto.ini」に登録された音源とその設定値のリスト、
右上が選択した音源に対して編集を行うための操作部、下は選択した音源の波形を表示する部分、となっています。 

音源ファイルのリスト
各列は列のヘッダーの表示のとおり。「FRQ」の列は、UTAUのresamplerが参照する*.frqファイルが準備済みかどうかを表し、
「STF」の列は、STRAIGHT合成に必要な解析ファイル（拡張子.stf）が準備済みかどうかを表します。それぞれ、準備済みの場合は「○」、そうでない場合は空欄となります。 

操作部
左のリストで選択した音源の設定値を編集します。テキストボックスに入力した値は、即リストに反映されます。
ただし、「ファイル」→「保存」または「名前をつけて保存」を選ばない限りoto.iniへの保存は行われません。 

「STFを更新」ボタンを押すと、選択した音源を元にSTRAIGHT用の解析ファイルを作成します。既にSTFが作成済みの場合も、
上書きされます。すべての音源のSTFファイルを連続で作成したい場合、「編集」→「STFファイルを作成」を選べばOKです。 

波形表示部
波形を表示しています。時間軸方向の拡大率は右下の「＋」「－」ボタンで変更できます。波形が画面に収まらない場合は、
スクロールバーで表示位置を横方向に移動できます。また、マウスの中ボタンで画面を掴んで移動させることも可能です。 

この画面上でオフセット等の設定を編集することができます。「オフセット」、「先行発音」等と書かれた旗状のものを掴んで移動させると、編集結果が即反映されます。 
波形表示部の何も無いところでマウスの左ボタンを降ろすと、ボタンを降ろした位置から音源ファイルが再生されます。どの部分までが子音的かを調べるとき等に便利かもしれません。

「ファイル」メニュー
 「開く」「保存」「名前をつけて保存」「終了」のサブ項目があります。

「編集」メニュー
サブ項目「STFファイルを作成」と「FRQファイルを作成」があります。それぞれ，STFファイルとFRQファイルを連続的に自動で作成するための項目です。
既にSTFファイルまたはFRQファイルが存在する場合は上書きは行われず、処理がスキップされます。個別の音源についてひとつづつSTFファイル／FRQファイルを作成したい場合は、
対象の音源をリストで選択したうえで、操作部の「STFを更新」ボタンまたは「FRQを更新」を押せばOKです。 

・音声合成エンジンを「STRAIGHT x UTAU」モードにする。
合成エンジンのモードは各トラック毎に設定します．設定するには，「トラック」メニュー→「音声合成エンジン」メニュー→「STRAIGHT x UTAU」と選択してください。
画面下のトラックのリストを右クリックし，コンテキストメニューの「音声合成エンジン」→「STRAIGHT x UTAU」を選択することでも，設定可能です。

■鍵盤用音源生成ユーティリティ 
鍵盤を押したときに再生される音声ファイルを、自動で作成するユーティリティ「GenerateKeySound.exe」について。 
GenerateKeySoundはコマンドラインツールとしても、GUIインターフェイス付きのツールとしても使用できるようになっています。コマンドライン引数は、
「GenerateKeySound -h」と入力して確認してください。ここでは、GUIの操作について説明します。 

Singing Synth. System
歌声合成システムの種類を選択します。「VOCALOID1」、「VOCALOID2」および「UTAU」のうち、使用できるものがリストに列挙されています。

Singer
鍵盤用の音声を担当する歌手を選択します。上で選択した歌声合成システムのうち、使用可能な歌手がリストに列挙されています。

Ignore Existing WAVs
ここにチェックを入れると、既に作成済みの音源ファイルを無視して上書きします。チェックを入れない場合、作成が未だのもののみを生成します。

Output Path
音源ファイルを保存するパスを指定します。すぐ右の「...」ボタンを押してパスを選択するか、テキストボックスに直接パスを入力してください。デフォルトでは、
「Cadenciiのインストールフォルダ￥cache」となっています。このデフォルトのパスではない場所に音源ファイルを保存することは出来ますが、Cadencii本体には認識されません。
Cadenciiが認識するのは、上記デフォルトのパスのみです。

Closeボタン
ウィンドウを閉じます。音源ファイルの生成中は「Cancel」と表記が変わり、このボタンを押すと音源ファイルの生成が中断されます。

Executeボタン
音源ファイルの生成を開始します。

■自動バックアップ機能 
一定時間おきに編集中のデータを保存する機能です。 

この機能を使うには、「設定」→「プリファレンス」→「ファイル」タブの「自動バックアップ」のチェックをONにしてください。
保存間隔はすぐ横の「間隔」のところで1分刻みで設定できます。 
この機能がONになっているとき、現在編集中のファイルと同じフォルダに、2つのバックアップファイル「~$ファイル名.xvsq」と「~$ファイル名.vsq」が保存されます。 

※クラッシュ後の自動復帰機能はありませんので注意ください。 

■英語表記→日本語表記にする方法。
「Setting」メニュー　→　「Preference」メニューとたどると，設定ダイアログがでます。 
このダイアログの「Appearnce」タブを選び，中ほどの「UI Language」を「Default」から「ja」に変更した後， 
「OK」を押せば，表示が日本語に変更されます。

■ベジエ曲線の編集
ベジエ曲線の編集をする場合、編集モードを「カーブ」モードにする必要があります。このモードに切り替えるには、
右クリックメニューの「カーブ」をクリックするか、編集バーの「カーブ」アイコンをクリックしてください（アイコンは
本家にはない奴なのですぐにわかると思います）。カーブモードになっていない場合、本家と同様に鉛筆、ラインと消しゴムの
各ツールを使って直接曲線を編集するモードとなります。 

編集には「鉛筆ツール」と「ポインタツール」を使います。鉛筆ツールはデータ点を追加する時に使用します。マウスをドラッグせずに単にクリックした場合、
制御点の付いていないデータ点が作成されます。

ポインタツールは、データ点（緑色）と制御点（桃色）の位置を変更する時に使用します。データ点の四角をマウスでドラッグすると、点が移動します。
マウスを動かしている途中で点が移動しなくなることがありますが、これは曲線が逆行するようなデータ点は入力できないためです。 

データ点を削除したい場合、データ点を右クリックすると出てくるメニューの「削除」をクリックします。 

データ点の座標を数値入力したい場合、データ点をダブルクリックすると数値入力用のダイアログが出ます。 

最初は折れ線としてデータを入力したが、途中で制御点をつけて滑らかにしたい場合や、その逆の場合、
数値入力用ダイアログの「滑らかにする」のチェックをOn/Offすることで、制御点を付ける／付けないを切り替えることが出来ます。 

・ベジエ曲線を使って編集するとき、1本のベジエ曲線ではなく、2本以上に分けて編集する場合。
コントロールキー（Macの場合Commandキー）を押しながら点を打ってください。直前の曲線と接続されず、新規のベジエ曲線が作成されます。 

●スクリプトのサンプル
編集自動化スクリプトのサンプル

スクリプトの呼び出し仕様などが確定していないので，下記のサンプルは疑似コードです。

・試してみたい方は、それぞれのスクリプトのソースコードと思しき部分をテキストファイルにコピペして UTF-8 で保存し、
　Cadencii.exeの置いてあるフォルダ直下の「script」というフォルダに入れてください。

・トラックの内容をUTAUの「resampler*.exe」と「wavtool.exe」を使ってレンダリングするスクリプト
※•エンベロープをはじめとした各種パラメータは設定・反映されません。

・UTAU音源でレンダリング

// Render As UTAU.cs for Cadencii
// written by kbinani & 88
using System;
using System.Collections.Generic;
using System.IO;
using System.Windows.Forms;
using Boare.Lib.Vsq;
using Boare.Lib.AppUtil;
using bocoree;
 
public class RenderAsUtau : Form {
    private System.ComponentModel.IContainer components = null;
    public static string Resampler = "";
    public static string WavTool = "";
    public static string Singer = "";
    public static string LastWave = "";
    public static bool InvokeWithWine = false;
    private Label lblResampler;
    private TextBox txtSinger;
    private Button btnSinger;
    private GroupBox groupConfig;
    private Button btnWavtool;
    private Button btnResampler;
    private TextBox txtWavtool;
    private TextBox txtResampler;
    private Label lblWavtool;
    private Button btnOk;
    private FolderBrowserDialog folderBrowserDialog;
    private OpenFileDialog openFileDialog;
    private PictureBox pictSumbnail;
    private TextBox txtProf;
    private GroupBox groupSinger;
    private Label lblName;
    private static SaveFileDialog saveFileDialog;
    private CheckBox chkInvokeWithWine;
    private Label lblDirectory;
    private Button btnCancel;
 
    struct Phon {
        public string Lyric;
        public string FileName;
        public int ClockLength;
        public float Tempo;
        public bool ModeR;
        public Phon( string lyric, string file_name, int clock_length, float tempo, bool mode_r ) {
            Lyric = lyric;
            FileName = file_name;
            ClockLength = clock_length;
            Tempo = tempo;
            ModeR = mode_r;
        }
    }
 
    /// <summary>
    /// 原音設定の引数．
    /// </summary>
    struct OtoArgs {
        /// <summary>
        /// 第1引数．空文字なので使わない
        /// </summary>
        public int A1;
        public int A2;
        public int A3;
        public int A4;
        public int A5;
        public int A6;
    }
 
    public RenderAsUtau() {
        InitializeComponent();
        txtResampler.Text = Resampler;
        txtWavtool.Text = WavTool;
        txtSinger.Text = Singer;
        folderBrowserDialog.SelectedPath = Singer;
        chkInvokeWithWine.Checked = InvokeWithWine;
        saveFileDialog = new SaveFileDialog();
        if ( LastWave != "" ) {
            try {
                saveFileDialog.InitialDirectory = Path.GetDirectoryName( LastWave );
            } catch {
            }
        }
        saveFileDialog.Filter = "Wave File(*.wav)|*.wav|All Files(*.*)|*.*";
 
        bool entered = false;
        if ( txtResampler.Text != "" ) {
            try {
                string dir = Path.GetDirectoryName( txtResampler.Text );
                openFileDialog.InitialDirectory = dir;
                entered = true;
            } catch {
            }
        }
        if ( !entered && txtWavtool.Text != "" ) {
            try {
                string dir = Path.GetDirectoryName( txtWavtool.Text );
                openFileDialog.InitialDirectory = dir;
                entered = true;
            } catch {
            }
        }
        CheckOkButtonAvailable();
        UpdateProfile();
        ApplyLanguage();
    }
 
    void ApplyLanguage() {
        if ( Messaging.Language == "ja" ) {
            groupSinger.Text = "音源";
            groupConfig.Text = "設定";
            btnCancel.Text = "取消";
            btnOk.Text = "了解";
            btnSinger.Text = "探す";
            btnResampler.Text = "探す";
            btnWavtool.Text = "探す";
            chkInvokeWithWine.Text = "wine経由でUTAUコアを起動";
            lblDirectory.Text = "音源フォルダ";
        }
    }
 
    void UpdateProfile() {
        if ( Singer == "" || !Directory.Exists( Singer ) ) {
            pictSumbnail.Image = null;
            lblName.Text = "(Unknown)";
            return;
        }
        string character = Path.Combine( Singer, "character.txt" );
        if ( File.Exists( character ) ) {
            using ( cp932reader sr = new cp932reader( character ) ) {
                string line = "";
                while ( (line = sr.ReadLine()) != null ) {
                    string[] spl = line.Split( "=".ToCharArray(), 2 );
                    if ( spl.Length >= 2 ) {
                        if ( spl[0].ToLower() == "name" ) {
                            lblName.Text = spl[1];
                        } else if ( spl[0].ToLower() == "image" ) {
                            string image = Path.Combine( Singer, spl[1] );
                            if ( File.Exists( image ) ) {
                                try {
                                    pictSumbnail.Image = System.Drawing.Bitmap.FromFile( image );
                                } catch {
                                }
                            }
                        }
                    }
                }
            }
        }
 
        string readme = Path.Combine( Singer, "readme.txt" );
        if ( File.Exists( readme ) ) {
            using ( cp932reader sr = new cp932reader( readme ) ) {
                txtProf.Text = sr.ReadToEnd();
            }
        } else {
            txtProf.Text = "";
        }
    }
 
    public static bool Edit( VsqFile vsq ) {
        using ( RenderAsUtau dlg = new RenderAsUtau() ) {
            if ( dlg.ShowDialog() == DialogResult.OK ) {
                Singer = dlg.txtSinger.Text;
                Resampler = dlg.txtResampler.Text;
                WavTool = dlg.txtWavtool.Text;
                string script = Path.Combine( Application.StartupPath, Path.Combine( "script", "Render As UTAU.cs" ) );//Script.ScriptPath;
                string temp_dir = Path.Combine( Path.GetDirectoryName( script ), Path.GetFileNameWithoutExtension( script ) );
 
#if DEBUG
                StreamWriter sw = new StreamWriter( Path.Combine( temp_dir, "log.txt" ) );
#endif
                // 原音設定を読み込み
                Dictionary<string, OtoArgs> config = new Dictionary<string, OtoArgs>();
                string singer_name = Path.GetFileName( Singer );
                string config_file = Path.Combine( Singer, "oto.ini" );
#if DEBUG
                sw.WriteLine( "Singer=" + Singer );
                sw.WriteLine( "singer_name=" + singer_name );
                sw.WriteLine( "config_file=" + config_file );
#endif
                if ( File.Exists( config_file ) ) {
                    using ( cp932reader sr = new cp932reader( config_file ) ) {
                        string line;
                        while ( sr.Peek() >= 0 ) {
                            line = sr.ReadLine();
                            string[] spl = line.Split( '=' );
                            string a1 = spl[0];
                            string a2 = spl[1];
                            int index = a1.IndexOf( ".wav" );
                            a1 = a1.Substring( 0, index );
                            spl = a2.Split( ',' );
                            OtoArgs oa = new OtoArgs();
                            oa.A1 = 0;
                            oa.A2 = int.Parse( spl[1] );
                            oa.A3 = int.Parse( spl[2] );
                            oa.A4 = int.Parse( spl[3] );
                            oa.A5 = int.Parse( spl[4] );
                            oa.A6 = int.Parse( spl[5] );
                            config.Add( a1, oa );
                        }
                    }
                }
 
                int track = Script.Manager.Selected;
                List<Phon> phons = new List<Phon>();
                if ( !Directory.Exists( temp_dir ) ) {
                    Directory.CreateDirectory( temp_dir );
                }
                int count = -1;
                double sec_end = 0;
                double sec_end_old = 0;
                foreach ( VsqEvent item in vsq.Tracks[track].GetNoteEventEnumerator() ) {
                    count++;
                    double sec_start = vsq.SecFromClock( item.Clock );
                    sec_end_old = sec_end;
                    sec_end = vsq.SecFromClock( item.Clock + item.ID.Length );
                    float t_temp = (float)(item.ID.Length / (sec_end - sec_start) / 8.0);
                    if ( (count == 0 && sec_start > 0.0) || (sec_start > sec_end_old) ) {
                        double sec_start2 = sec_end_old;
                        double sec_end2 = sec_start;
                        float t_temp2 = (float)(item.Clock / (sec_end2 - sec_start2) / 8.0);
                        phons.Add( new Phon( "R", Path.Combine( Singer, "R.wav" ), item.Clock, t_temp2, true ) );
                        count++;
                    }
                    string lyric = item.ID.LyricHandle.L0.Phrase;
                    string note = NoteStringFromNoteNumber( item.ID.Note );
#if DEBUG
                    sw.WriteLine( "note=" + note );
#endif
                    string millisec = ((int)((sec_end - sec_start) * 1000) + 50).ToString();
 
                    //4_あ_C#4_550.wav
                    string filename = Path.Combine( temp_dir, count + "_" + item.ID.Note + "_" + millisec + ".wav" );
#if DEBUG
                    sw.WriteLine( "filename=" + filename );
                    sw.WriteLine();
#endif
                    if ( File.Exists( filename ) ) {
                        File.Delete( filename );
                    }
 
                    phons.Add( new Phon( lyric, filename, item.ID.Length, t_temp, false ) );
 
                    OtoArgs oa = new OtoArgs();
                    if ( config.ContainsKey( lyric ) ) {
                        oa = config[lyric];
                    }
                    string arg = "\"" + Path.Combine( Singer, lyric + ".wav" ) + "\" \"" + filename + "\" \"" + note + "\" 100 L " + oa.A2 + " " + millisec + " " + oa.A3 + " " + oa.A4 + " 100 100";
 
                    using ( System.Diagnostics.Process p = new System.Diagnostics.Process() ) {
                        p.StartInfo.FileName = (InvokeWithWine ? "wine \"" : "\"") + Resampler + "\"";
                        p.StartInfo.Arguments = arg;
                        p.StartInfo.WorkingDirectory = temp_dir;
                        p.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
                        p.Start();
                        p.WaitForExit();
                    }
                }
#if DEBUG
                sw.Close();
#endif
 
                string filebase = "temp.wav";
                string file = Path.Combine( temp_dir, filebase );
                if ( File.Exists( file ) ) {
                    File.Delete( file );
                }
                string file_whd = Path.Combine( temp_dir, filebase + ".whd" );
                if ( File.Exists( file_whd ) ) {
                    File.Delete( file_whd );
                }
                string file_dat = Path.Combine( temp_dir, filebase + ".dat" );
                if ( File.Exists( file_dat ) ) {
                    File.Delete( file_dat );
                }
 
                // wavtoolを呼び出す
                for ( int i = 0; i < phons.Count; i++ ) {
                    OtoArgs oa = new OtoArgs();
                    if ( config.ContainsKey( phons[i].Lyric ) ) {
                        oa = config[phons[i].Lyric];
                    }
                    // 次の音符の先行発声とオーバーラップを取得
                    OtoArgs oa_next = new OtoArgs();
                    if ( i + 1 < phons.Count ) {
                        if ( config.ContainsKey( phons[i + 1].Lyric ) ) {
                            oa_next = config[phons[i + 1].Lyric];
                        }
                    }
                    int mten = oa.A5 + oa_next.A6 - oa_next.A5;
                    string arg = filebase + " \"" + phons[i].FileName + "\" 0 " + phons[i].ClockLength + "@" + string.Format( "{0:f2}", phons[i].Tempo ) + mten.ToString( "+#;-#;0" );
                    if ( phons[i].ModeR ) {
                        arg += " 0 0";
                    } else {
                        arg += " 0 5 35 0 100 100 100 " + oa.A6; // エンベロープ
                    }
 
                    using ( System.Diagnostics.Process p = new System.Diagnostics.Process() ) {
                        p.StartInfo.FileName = (InvokeWithWine ? "wine \"" : "\"") + WavTool + "\"";
                        p.StartInfo.Arguments = arg;
                        p.StartInfo.WorkingDirectory = temp_dir;
                        p.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
                        p.Start();
                        p.WaitForExit();
                    }
                }
 
                // 波形とヘッダを結合
                using ( FileStream fs = new FileStream( file, FileMode.Create ) ) {
                    string[] files = new string[] { file_whd, file_dat };
                    int buflen = 512;
                    byte[] buff = new byte[buflen];
                    for ( int i = 0; i < files.Length; i++ ) {
                        using ( FileStream fs2 = new FileStream( files[i], FileMode.Open ) ) {
                            int len = fs2.Read( buff, 0, buflen );
                            while ( len > 0 ) {
                                fs.Write( buff, 0, len );
                                len = fs2.Read( buff, 0, buflen );
                            }
                        }
                    }
                }
 
                // 後片付け
                foreach ( Phon ph in phons ) {
                    if ( !ph.ModeR ) {
                        if ( File.Exists( ph.FileName ) ) {
                            File.Delete( ph.FileName );
                        }
                    }
                }
                if ( File.Exists( file_whd ) ) {
                    File.Delete( file_whd );
                }
                if ( File.Exists( file_dat ) ) {
                    File.Delete( file_dat );
                }
 
                if ( saveFileDialog.ShowDialog() == DialogResult.OK ) {
                    if ( File.Exists( saveFileDialog.FileName ) ) {
                        File.Delete( saveFileDialog.FileName );
                    }
                    LastWave = saveFileDialog.FileName;
                    File.Move( file, saveFileDialog.FileName );
                } else {
                    File.Delete( file );
                }
                return true;
            } else {
                return false;
            }
        }
    }
 
    private static string NoteStringFromNoteNumber( int note_number ) {
        int odd = note_number % 12;
        string head = (new string[] { "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B" })[odd];
        return head + (note_number / 12 - 1);
    }
 
    protected override void Dispose( bool disposing ) {
        if ( disposing && (components != null) ) {
            components.Dispose();
        }
        base.Dispose( disposing );
    }
 
    private void InitializeComponent() {
        this.lblResampler = new System.Windows.Forms.Label();
        this.txtSinger = new System.Windows.Forms.TextBox();
        this.btnSinger = new System.Windows.Forms.Button();
        this.groupConfig = new System.Windows.Forms.GroupBox();
        this.chkInvokeWithWine = new System.Windows.Forms.CheckBox();
        this.btnWavtool = new System.Windows.Forms.Button();
        this.btnResampler = new System.Windows.Forms.Button();
        this.txtWavtool = new System.Windows.Forms.TextBox();
        this.txtResampler = new System.Windows.Forms.TextBox();
        this.lblWavtool = new System.Windows.Forms.Label();
        this.btnOk = new System.Windows.Forms.Button();
        this.btnCancel = new System.Windows.Forms.Button();
        this.folderBrowserDialog = new System.Windows.Forms.FolderBrowserDialog();
        this.openFileDialog = new System.Windows.Forms.OpenFileDialog();
        this.pictSumbnail = new System.Windows.Forms.PictureBox();
        this.txtProf = new System.Windows.Forms.TextBox();
        this.groupSinger = new System.Windows.Forms.GroupBox();
        this.lblName = new System.Windows.Forms.Label();
        this.lblDirectory = new System.Windows.Forms.Label();
        this.groupConfig.SuspendLayout();
        ((System.ComponentModel.ISupportInitialize)(this.pictSumbnail)).BeginInit();
        this.groupSinger.SuspendLayout();
        this.SuspendLayout();
        // 
        // lblResampler
        // 
        this.lblResampler.AutoSize = true;
        this.lblResampler.Location = new System.Drawing.Point( 11, 29 );
        this.lblResampler.Name = "lblResampler";
        this.lblResampler.Size = new System.Drawing.Size( 55, 12 );
        this.lblResampler.TabIndex = 0;
        this.lblResampler.Text = "resampler";
        // 
        // txtSinger
        // 
        this.txtSinger.Location = new System.Drawing.Point( 98, 176 );
        this.txtSinger.Name = "txtSinger";
        this.txtSinger.Size = new System.Drawing.Size( 215, 19 );
        this.txtSinger.TabIndex = 2;
        this.txtSinger.TextChanged += new System.EventHandler( this.txtSinger_TextChanged );
        // 
        // btnSinger
        // 
        this.btnSinger.Location = new System.Drawing.Point( 319, 174 );
        this.btnSinger.Name = "btnSinger";
        this.btnSinger.Size = new System.Drawing.Size( 56, 23 );
        this.btnSinger.TabIndex = 3;
        this.btnSinger.Text = "Browse";
        this.btnSinger.UseVisualStyleBackColor = true;
        this.btnSinger.Click += new System.EventHandler( this.btnSinger_Click );
        // 
        // groupConfig
        // 
        this.groupConfig.Controls.Add( this.chkInvokeWithWine );
        this.groupConfig.Controls.Add( this.btnWavtool );
        this.groupConfig.Controls.Add( this.btnResampler );
        this.groupConfig.Controls.Add( this.txtWavtool );
        this.groupConfig.Controls.Add( this.txtResampler );
        this.groupConfig.Controls.Add( this.lblWavtool );
        this.groupConfig.Controls.Add( this.lblResampler );
        this.groupConfig.Location = new System.Drawing.Point( 14, 236 );
        this.groupConfig.Name = "groupConfig";
        this.groupConfig.Size = new System.Drawing.Size( 394, 106 );
        this.groupConfig.TabIndex = 4;
        this.groupConfig.TabStop = false;
        this.groupConfig.Text = "Configuration";
        // 
        // chkInvokeWithWine
        // 
        this.chkInvokeWithWine.AutoSize = true;
        this.chkInvokeWithWine.Location = new System.Drawing.Point( 13, 76 );
        this.chkInvokeWithWine.Name = "chkInvokeWithWine";
        this.chkInvokeWithWine.Size = new System.Drawing.Size( 110, 16 );
        this.chkInvokeWithWine.TabIndex = 8;
        this.chkInvokeWithWine.Text = "Invoke with Wine";
        this.chkInvokeWithWine.UseVisualStyleBackColor = true;
        this.chkInvokeWithWine.CheckedChanged += new System.EventHandler( this.chkInvokeWithWine_CheckedChanged );
        // 
        // btnWavtool
        // 
        this.btnWavtool.Location = new System.Drawing.Point( 319, 49 );
        this.btnWavtool.Name = "btnWavtool";
        this.btnWavtool.Size = new System.Drawing.Size( 56, 23 );
        this.btnWavtool.TabIndex = 7;
        this.btnWavtool.Text = "Browse";
        this.btnWavtool.UseVisualStyleBackColor = true;
        this.btnWavtool.Click += new System.EventHandler( this.btnWavtool_Click );
        // 
        // btnResampler
        // 
        this.btnResampler.Location = new System.Drawing.Point( 319, 24 );
        this.btnResampler.Name = "btnResampler";
        this.btnResampler.Size = new System.Drawing.Size( 56, 23 );
        this.btnResampler.TabIndex = 5;
        this.btnResampler.Text = "Browse";
        this.btnResampler.UseVisualStyleBackColor = true;
        this.btnResampler.Click += new System.EventHandler( this.btnResampler_Click );
        // 
        // txtWavtool
        // 
        this.txtWavtool.Location = new System.Drawing.Point( 77, 51 );
        this.txtWavtool.Name = "txtWavtool";
        this.txtWavtool.Size = new System.Drawing.Size( 236, 19 );
        this.txtWavtool.TabIndex = 6;
        this.txtWavtool.TextChanged += new System.EventHandler( this.txtWavtool_TextChanged );
        // 
        // txtResampler
        // 
        this.txtResampler.Location = new System.Drawing.Point( 77, 26 );
        this.txtResampler.Name = "txtResampler";
        this.txtResampler.Size = new System.Drawing.Size( 236, 19 );
        this.txtResampler.TabIndex = 5;
        this.txtResampler.TextChanged += new System.EventHandler( this.txtResampler_TextChanged );
        // 
        // lblWavtool
        // 
        this.lblWavtool.AutoSize = true;
        this.lblWavtool.Location = new System.Drawing.Point( 11, 54 );
        this.lblWavtool.Name = "lblWavtool";
        this.lblWavtool.Size = new System.Drawing.Size( 44, 12 );
        this.lblWavtool.TabIndex = 1;
        this.lblWavtool.Text = "wavtool";
        // 
        // btnOk
        // 
        this.btnOk.DialogResult = System.Windows.Forms.DialogResult.OK;
        this.btnOk.Location = new System.Drawing.Point( 252, 356 );
        this.btnOk.Name = "btnOk";
        this.btnOk.Size = new System.Drawing.Size( 75, 23 );
        this.btnOk.TabIndex = 6;
        this.btnOk.Text = "OK";
        this.btnOk.UseVisualStyleBackColor = true;
        // 
        // btnCancel
        // 
        this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
        this.btnCancel.Location = new System.Drawing.Point( 333, 356 );
        this.btnCancel.Name = "btnCancel";
        this.btnCancel.Size = new System.Drawing.Size( 75, 23 );
        this.btnCancel.TabIndex = 7;
        this.btnCancel.Text = "Cancel";
        this.btnCancel.UseVisualStyleBackColor = true;
        // 
        // openFileDialog
        // 
        this.openFileDialog.FileName = "openFileDialog1";
        // 
        // pictSumbnail
        // 
        this.pictSumbnail.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
        this.pictSumbnail.Location = new System.Drawing.Point( 18, 52 );
        this.pictSumbnail.Name = "pictSumbnail";
        this.pictSumbnail.Size = new System.Drawing.Size( 100, 100 );
        this.pictSumbnail.TabIndex = 8;
        this.pictSumbnail.TabStop = false;
        // 
        // txtProf
        // 
        this.txtProf.BackColor = System.Drawing.SystemColors.Window;
        this.txtProf.Location = new System.Drawing.Point( 131, 47 );
        this.txtProf.Multiline = true;
        this.txtProf.Name = "txtProf";
        this.txtProf.ReadOnly = true;
        this.txtProf.ScrollBars = System.Windows.Forms.ScrollBars.Both;
        this.txtProf.Size = new System.Drawing.Size( 247, 111 );
        this.txtProf.TabIndex = 9;
        this.txtProf.WordWrap = false;
        // 
        // groupSinger
        // 
        this.groupSinger.Controls.Add( this.lblDirectory );
        this.groupSinger.Controls.Add( this.lblName );
        this.groupSinger.Controls.Add( this.pictSumbnail );
        this.groupSinger.Controls.Add( this.txtProf );
        this.groupSinger.Controls.Add( this.txtSinger );
        this.groupSinger.Controls.Add( this.btnSinger );
        this.groupSinger.Location = new System.Drawing.Point( 14, 12 );
        this.groupSinger.Name = "groupSinger";
        this.groupSinger.Size = new System.Drawing.Size( 394, 218 );
        this.groupSinger.TabIndex = 10;
        this.groupSinger.TabStop = false;
        this.groupSinger.Text = "Singer";
        // 
        // lblName
        // 
        this.lblName.AutoSize = true;
        this.lblName.Font = new System.Drawing.Font( "MS UI Gothic", 9.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(128)) );
        this.lblName.Location = new System.Drawing.Point( 21, 23 );
        this.lblName.Name = "lblName";
        this.lblName.Size = new System.Drawing.Size( 74, 13 );
        this.lblName.TabIndex = 10;
        this.lblName.Text = "(Unknown)";
        // 
        // lblDirectory
        // 
        this.lblDirectory.AutoSize = true;
        this.lblDirectory.Location = new System.Drawing.Point( 11, 179 );
        this.lblDirectory.Name = "lblDirectory";
        this.lblDirectory.Size = new System.Drawing.Size( 81, 12 );
        this.lblDirectory.TabIndex = 11;
        this.lblDirectory.Text = "voice directory";
        // 
        // RenderAsUtau
        // 
        this.AcceptButton = this.btnOk;
        this.AutoScaleDimensions = new System.Drawing.SizeF( 6F, 12F );
        this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
        this.CancelButton = this.btnCancel;
        this.ClientSize = new System.Drawing.Size( 420, 393 );
        this.Controls.Add( this.groupSinger );
        this.Controls.Add( this.btnCancel );
        this.Controls.Add( this.btnOk );
        this.Controls.Add( this.groupConfig );
        this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
        this.MaximizeBox = false;
        this.MinimizeBox = false;
        this.Name = "RenderAsUtau";
        this.ShowIcon = false;
        this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
        this.Text = "Render As UTAU";
        this.groupConfig.ResumeLayout( false );
        this.groupConfig.PerformLayout();
        ((System.ComponentModel.ISupportInitialize)(this.pictSumbnail)).EndInit();
        this.groupSinger.ResumeLayout( false );
        this.groupSinger.PerformLayout();
        this.ResumeLayout( false );
 
    }
 
    private void btnSinger_Click( object sender, EventArgs e ) {
        if ( folderBrowserDialog.ShowDialog() == DialogResult.OK ) {
            txtSinger.Text = folderBrowserDialog.SelectedPath;
            UpdateProfile();
        }
    }
 
    private void CheckOkButtonAvailable() {
        if ( !File.Exists( Resampler ) || !File.Exists( WavTool ) || !Directory.Exists( Singer ) ) {
            btnOk.Enabled = false;
        } else {
            btnOk.Enabled = true;
        }
    }
 
    private void btnResampler_Click( object sender, EventArgs e ) {
        if ( openFileDialog.ShowDialog() == DialogResult.OK ) {
            txtResampler.Text = openFileDialog.FileName;
        }
    }
 
    private void btnWavtool_Click( object sender, EventArgs e ) {
        if ( openFileDialog.ShowDialog() == DialogResult.OK ) {
            txtWavtool.Text = openFileDialog.FileName;
        }
    }
 
    private void txtResampler_TextChanged( object sender, EventArgs e ) {
        Resampler = txtResampler.Text;
        CheckOkButtonAvailable();
    }
 
    private void txtWavtool_TextChanged( object sender, EventArgs e ) {
        WavTool = txtWavtool.Text;
        CheckOkButtonAvailable();
    }
 
    private void txtSinger_TextChanged( object sender, EventArgs e ) {
        Singer = txtSinger.Text;
        CheckOkButtonAvailable();
        UpdateProfile();
    }
 
    private void chkInvokeWithWine_CheckedChanged( object sender, EventArgs e ) {
        InvokeWithWine = chkInvokeWithWine.Checked;
    }
}
 
・メタテキストの内容をファイルに保存する

public static class SaveMetaText {
    public static bool Edit( Boare.Lib.Vsq.VsqFile vsq ) {
        vsq.Track[1].printMetaText( @"c:\meta_text.txt" );
        return true;
    }
}

・歌詞情報を取得し、ファイルに保存する

public static class PrintLyric {
    public static bool Edit( Boare.Lib.Vsq.VsqFile Vsq ) {
        System.IO.StreamWriter sw = null;
        try {
            sw = new System.IO.StreamWriter( @"c:\lyrics.txt" );
            for ( Boare.Lib.Vsq.Iterator itr = Vsq.Track[1].getNoteEventIterator(); itr.hasNext(); ) {
                Boare.Lib.Vsq.VsqEvent item = (Boare.Lib.Vsq.VsqEvent)itr.next();
                int clStart = item.Clock;
                int clEnd = clStart + item.ID.Length;
                double secStart = Vsq.getSecFromClock( clStart );
                double secEnd = Vsq.getSecFromClock( clEnd );
                sw.WriteLine( secStart + "\t" + secEnd + "\t" + item.ID.LyricHandle.L0.Phrase + "\t" + item.ID.LyricHandle.L0.PhoneticSymbol );
            }
        } catch {
            return false;
        } finally {
            if ( sw != null ) {
                sw.Close();
            }
        }
        return true;
    }
}

・全ての音符を半音上げる

public static class UpHalfStep {
    public static bool Edit( Boare.Lib.Vsq.VsqFile Vsq ) {
        for ( int i = 1; i < Vsq.Track.Count; i++ ) {
            for ( Boare.Lib.Vsq.Iterator itr = Vsq.Track[i].getNoteEventIterator(); itr.hasNext(); ) {
                Boare.Lib.Vsq.VsqEvent item = (Boare.Lib.Vsq.VsqEvent)itr.next();
                if ( item.ID.Note < 127 ) {
                    item.ID.Note++;
                }
            }
        }
        return true;
    }
}

・全ての音符の長さを32分音符分だけ短くする

public static class Trim32 {
    public static bool Edit( Boare.Lib.Vsq.VsqFile Vsq ) {
        for ( int i = 1; i < Vsq.Track.Count; i++ ) {
            for ( Boare.Lib.Vsq.Iterator itr = Vsq.Track[i].getNoteEventIterator(); itr.hasNext(); ) {
                Boare.Lib.Vsq.VsqEvent item = (Boare.Lib.Vsq.VsqEvent)itr.next();
                // 32分音符の長さは，クロック数に直すと60クロック
                if ( item.ID.Length > 60 ) {
                    item.ID.Length -= 60;
                }
            }
        }
        return true;
    }
}
















