« CVシリーズ Vocal CD Volume 01 星のカケラ | トップページ | melody...3D PV ver1.50 »

初音ミクに喋らせてみた(Perl版004)

初音ミクに喋らせるスクリプトをちょっとだけバージョンアップしてみました。
相変わらずハードコーディングですが、$myTalk の文字列(平仮名のみ限定)を書き換えることで、任意文字列の発音ができるようにしています。

ハードコーディングしている理由は、エラー処理をしていない為です。たぶん半角文字やカタカナを入れるとミクが黙りこむとおもいます。親切に実行手順を書いていないのは、「まだα版なので、わかる人だけ触ってください」という趣旨です。

Perl スクリプトと、生成される VSQファイルは以下のものです。
「miku_talk004.zip」をダウンロード

生成される音声は「わたしわ、はつねみく。わたしわ、しゃべるのがすき」です。音声ファイルと照合してください。
「test_miku004.mp3」をダウンロード

そして、ソースコードはこちら。ちょっとだけ手を入れて美化。

#!/Perl
########################################################################
#    miku_talk ver.0.0.4
#
#   Programmed by Akira Izumi
#   Ver.0.0.1:ハードコーディング"みく" ...  6/Dec/2007
#   Ver.0.0.4:任意の平仮名入力を受付ける...15/Dec/2007
#
use MIDI;
use Jcode;
use strict;
use warnings;

  my $myTalk = "わたしわ、はつねみく、わたしわ、しゃべるのがすき。";
  miku_VsqGenerate($myTalk,"test_miku004.vsq");
  exit(0);
#-----------------------------------------------------------------------
#
#    平仮名文字列からVSQファイルを生成する
#   第1引数:平仮名のみのテキスト文字列
#   第2引数:出力VSQファイル名
#
sub miku_VsqGenerate {
my $myStr2Talk  = $_[0];
my $myVsqFile   = $_[1];

#
# マスタートラックの定義
#
my @masterEvents = (
  ['track_name',    0, 'Master Track'],
  ['set_tempo',     0, 500_000], # 1qn = .50 seconds
  ['time_signature',0,4,2,24,8 ],
  ['end_track' ,    0],
);
#
# 平仮名からミク発音記号への変換ハッシュ表
#
my %phonetic =
("あ"=>"a",  "い"=>"i",   "う"=>"M",    "え"=>"e",    "お"=>"o",
"か"=>"k a","き"=>"k' i","く"=>"k M",  "け"=>"k e",  "こ"=>"k o",
"さ"=>"s a","し"=>"S i", "す"=>"s M",  "せ"=>"s e",  "そ"=>"s o",
"た"=>"t a","ち"=>"tS i","つ"=>"ts M", "て"=>"t e",  "と"=>"t o",
"な"=>"n a","に"=>"J i", "ぬ"=>"n M",  "ね"=>"n e",  "の"=>"n o",
"は"=>"h a","ひ"=>"C i", "ふ"=>"p\\ M","へ"=>"h e",  "ほ"=>"h o",
"ま"=>"m a","み"=>"m' i","む"=>"m M",  "め"=>"m e",  "も"=>"m o",
"や"=>"j a",             "ゆ"=>"j M",  "いぇ"=>"j e","よ"=>"j o",
"ら"=>"4 a","り"=>"4' i","る"=>"4 M",  "れ"=>"4 e",  "ろ"=>"4 o",
"わ"=>"w a",
#            "ゐ"=>"w i",        "ゑ"=>"w e",
  "を"=>"o",
             "うぃ"=>"w i",             "うぇ"=>"w e",
"ん"=>"n",
"んが"=>"N a",   "んぎ"=>"N i",   "んぐ"=>"N M",   "んげ"=>"N e",   "んご"=>"N o",
"んにゃ"=>"N' a","んにぃ"=>"N' i","んにゅ"=>"N' M","んにぇ"=>"N' e","んにょ"=>"N' o",

"が"=>"g a",   "ぎ"=>"g' i",  "ぐ"=>"g M",   "げ"=>"g e",   "ご"=>"g o",
"ざ"=>"dz a",  "じ"=>"dZ i",  "ず"=>"dz M",  "ぜ"=>"dz e",  "ぞ"=>"dz o",
"だ"=>"d a",   "ぢ"=>"dZ i",  "づ"=>"dz M",  "で"=>"d e",   "ど"=>"d o",
"ば"=>"b a",   "び"=>"b' i",  "ぶ"=>"b M",   "べ"=>"b e",   "ぼ"=>"b o",
"ぱ"=>"p a",   "ぴ"=>"p' i",  "ぷ"=>"p M",   "ぺ"=>"p e",   "ぽ"=>"p o",
"きゃ"=>"k' a","きぃ"=>"k' i","きゅ"=>"k' M","きぇ"=>"k' e","きょ"=>"k' o",
"しゃ"=>"S a", "しぃ"=>"S i", "しゅ"=>"S M", "しぇ"=>"S e", "しょ"=>"S o",
"ちゃ"=>"tS a","ちぃ"=>"tS i","ちゅ"=>"tS M","ちぇ"=>"tS e","ちょ"=>"tS o",
"にゃ"=>"J a", "にぃ"=>"J i", "にゅ"=>"J M", "にぇ"=>"J e", "にょ"=>"J o",
"ひゃ"=>"C a", "ひぃ"=>"C i", "ひゅ"=>"C M", "ひぇ"=>"C e", "ひょ"=>"C o",

"ふゃ"=>"p\\' a","ふぃ"=>"p\\' i","ふゅ"=>"p\\' M","ふぇ"=>"p\\' e","ふょ"=>"p\\' o",
"みゃ"=>"m' a","みぃ"=>"m' i","みゅ"=>"m' M","みぇ"=>"m' e","みょ"=>"m' o",
"りゃ"=>"4' a","りぃ"=>"4' i","りゅ"=>"4' M","りぇ"=>"4' e","りょ"=>"4' o",
"ぎゃ"=>"g' a","ぎぃ"=>"g' i","ぎゅ"=>"g' M","ぎぇ"=>"g' e","ぎょ"=>"g' o",
"じゃ"=>"Z a", "じぃ"=>"Z i", "じゅ"=>"Z M", "じぇ"=>"Z e", "じょ"=>"Z o",
"じゃ"=>"dZ a","じぃ"=>"dZ i","じゅ"=>"dZ M","じぇ"=>"dZ e","じょ"=>"dZ o",
"ぢゃ"=>"dZ a","ぢぃ"=>"dZ i","ぢゅ"=>"dZ M","ぢぇ"=>"dZ e","ぢょ"=>"dZ o",
"びゃ"=>"b' a","びぃ"=>"b' i","びゅ"=>"b' M","びぇ"=>"b' e","びょ"=>"b' o",
"ぴゃ"=>"p' a","ぴぃ"=>"p' i","ぴゅ"=>"p' M","ぴぇ"=>"p' e","ぴょ"=>"p' o",
"ふぁ"=>"p\\ a","ふぃ"=>"p\\ i","ふぅ"=>"p\\ M","ふぇ"=>"p\\ e","ふぉ"=>"p\\ o",
"てゃ"=>"t' a","てぃ"=>"t' i","てゅ"=>"t' M","てぇ"=>"t' e","てょ"=>"t' o",
"でゃ"=>"d' a","でぃ"=>"d' i","でゅ"=>"d' M","でぇ"=>"d' e","でょ"=>"d' o",
"ぁ"=>"h\\ a", "ぃ"=>"h\\ i",  "ぅ"=>"h\\ M","ぇ"=>"h\\ e", "ぉ"=>"h\\ o",
"っ"=>"tS  ",
"すぃ"=>"s i", "ずぃ"=>"dz i", "とぅ"=>"t M","どぅ"=>"d M");
#
# ミクの発音用テキストに於ける初期値の設定。
#
  my @myCommonSection =();
  push @myCommonSection, "[Common]";
  push @myCommonSection, "Version=DSB301";
  push @myCommonSection, "Name=Voice1";
  push @myCommonSection, "Color=181,162,123";
  push @myCommonSection, "DynamicsMode=1";
  push @myCommonSection, "PlayMode=1";

  my @myMasterSection =();
  push @myMasterSection, "[Master]";
  push @myMasterSection, "PreMeasure=4";

  my @myMixerSection =();
  push @myMixerSection, "[Mixer]";
  push @myMixerSection, "MasterFeder=0";
  push @myMixerSection, "MasterPanpot=0";
  push @myMixerSection, "MasterMute=0";
  push @myMixerSection, "OutputMode=0";
  push @myMixerSection, "Tracks=1";
  push @myMixerSection, "Feder0=0";
  push @myMixerSection, "Panpot0=0";
  push @myMixerSection, "Mute0=0";
  push @myMixerSection, "Solo0=0";

  my @myEventListSection =();
  push @myEventListSection, "[EventList]";
  push @myEventListSection, "0=ID#0000";

  my @myIDSection =();
  push @myIDSection, "[ID#0000]";
  push @myIDSection, "Type=Singer";
  push @myIDSection, "IconHandle=h#0000";

  my @myHandleSection =();
  push @myHandleSection, "[h#0000]";
  push @myHandleSection, "IconID=\$07010000";
  push @myHandleSection, "IDS=Miku";
  push @myHandleSection, "Original=0";
  push @myHandleSection, "Caption=";
  push @myHandleSection, "Length=1";
  push @myHandleSection, "Language=0";
  push @myHandleSection, "Program=0";
my @mikuMidiEvents = ();
  push @mikuMidiEvents,['control_change' , 0, 0,  99, 96];
  push @mikuMidiEvents,['control_change' , 0, 0,  98,  0];
  push @mikuMidiEvents,['control_change' , 0, 0,   6,  0];
  push @mikuMidiEvents,['control_change' , 0, 0,  38,  0];
  push @mikuMidiEvents,['control_change' , 0, 0,  98,  1];
  push @mikuMidiEvents,['control_change' , 0, 0,   6,  0];
  push @mikuMidiEvents,['control_change' , 0, 0,  38,  0];
  push @mikuMidiEvents,['control_change' , 0, 0,  98,  2];
  push @mikuMidiEvents,['control_change' , 0, 0,   6,  0];
  push @mikuMidiEvents,['control_change' , 0, 0,  99, 83];
  push @mikuMidiEvents,['control_change' , 0, 0,  98,  2];
  push @mikuMidiEvents,['control_change' , 0, 0,   6,  0];

#
# ミク発音(平仮名)を、ミク発音用メタデータに変換し、
#  同時にMIDIイベントを生成する。
#
  my $i=0;
  my $idxLyric = 0;
  my $pitch = 240;
  my $note = 64;
  for($i=0; $idxLyric<length($myStr2Talk); $i++ ) {
    my $myLyricLen = 6;
    my $myLyric = "";
    my $myPhonetic = "";
    for($myLyricLen=6; $myLyricLen>0; $myLyricLen-=2) {
      $myLyric = substr($myStr2Talk,$idxLyric,$myLyricLen);
      $myPhonetic = $phonetic{$myLyric};
      if( defined($myPhonetic) || $myLyricLen==2 ) {
        last;
      }
    }
    $idxLyric += $myLyricLen;

    if( defined($myPhonetic)) {
      push @myEventListSection, sprintf("%d=ID#%04d",$i*$pitch+7680,$i+1);
      push @myIDSection, sprintf("[ID#%04d]",$i+1);
      push @myIDSection, "Type=Anote";
      push @myIDSection, "Length=".$pitch;
      push @myIDSection, "Note#=".$note;
      push @myIDSection, "Dynamics=64";
      push @myIDSection, "PMBendDepth=20";
      push @myIDSection, "PMBendLength=0";
      push @myIDSection, "PMbPortamentoUse=0";
      push @myIDSection, "DEMdecGainRate=50";
      push @myIDSection, "DEMaccent=50";
      push @myIDSection, sprintf("LyricHandle=h#%04d",$i+1);
 
      push @myHandleSection, sprintf("[h#%04d]",$i+1);
      push @myHandleSection, "L0=\"".$myLyric."\",\"". $myPhonetic."\",1.000000,64,0,0";
    }
    if( $i==0 ) {
      push @mikuMidiEvents,['control_change', 5760, 0, 99,  80];
    } else {
      push @mikuMidiEvents,['control_change', $pitch, 0, 99,  80];
    }
    push @mikuMidiEvents,['control_change', 0, 0, 98,   0];
    push @mikuMidiEvents,['control_change', 0, 0,  6,   0];
    push @mikuMidiEvents,['control_change', 0, 0, 38,   0];
    push @mikuMidiEvents,['control_change', 0, 0, 98,   1];
    push @mikuMidiEvents,['control_change', 0, 0,  6,  15];
    push @mikuMidiEvents,['control_change', 0, 0, 38,  80];
    push @mikuMidiEvents,['control_change', 0, 0, 98,   2];
    push @mikuMidiEvents,['control_change', 0, 0,  6,  64];
    push @mikuMidiEvents,['control_change', 0, 0, 98,   3];
    push @mikuMidiEvents,['control_change', 0, 0,  6,  64];
    push @mikuMidiEvents,['control_change', 0, 0, 98,   4];
    push @mikuMidiEvents,['control_change', 0, 0,  6,   1];
    push @mikuMidiEvents,['control_change', 0, 0, 38, 122];
    push @mikuMidiEvents,['control_change', 0, 0, 98,   5];
    push @mikuMidiEvents,['control_change', 0, 0,  6,   1];
    push @mikuMidiEvents,['control_change', 0, 0, 98,  18];
    push @mikuMidiEvents,['control_change', 0, 0,  6,   3];
    push @mikuMidiEvents,['control_change', 0, 0, 98,  19];
    push @mikuMidiEvents,['control_change', 0, 0,  6, 109];
    push @mikuMidiEvents,['control_change', 0, 0, 38,  64];
    push @mikuMidiEvents,['control_change', 0, 0, 98,  20];
    push @mikuMidiEvents,['control_change', 0, 0,  6,  39];
    push @mikuMidiEvents,['control_change', 0, 0, 98,  21];
    push @mikuMidiEvents,['control_change', 0, 0,  6, 105];
    push @mikuMidiEvents,['control_change', 0, 0, 38,   0];
    push @mikuMidiEvents,['control_change', 0, 0, 98,  79];
    push @mikuMidiEvents,['control_change', 0, 0,  6, 127];
    push @mikuMidiEvents,['control_change', 0, 0, 98,  80];
    push @mikuMidiEvents,['control_change', 0, 0, 6,   12];
    push @mikuMidiEvents,['control_change', 0, 0, 98,  81];
    push @mikuMidiEvents,['control_change', 0, 0,  6,   8];
    push @mikuMidiEvents,['control_change', 0, 0, 98,  82];
    push @mikuMidiEvents,['control_change', 0, 0,  6,  20];
    push @mikuMidiEvents,['control_change', 0, 0, 98,  83];
    push @mikuMidiEvents,['control_change', 0, 0,  6,  28];
    push @mikuMidiEvents,['control_change', 0, 0, 98,  84];
    push @mikuMidiEvents,['control_change', 0, 0,  6,  24];
    push @mikuMidiEvents,['control_change', 0, 0, 98,  85];
    push @mikuMidiEvents,['control_change', 0, 0,  6,  10];
    push @mikuMidiEvents,['control_change', 0, 0, 98,  86];
    push @mikuMidiEvents,['control_change', 0, 0,  6,  12];
    push @mikuMidiEvents,['control_change', 0, 0, 98,  87];
    push @mikuMidiEvents,['control_change', 0, 0,  6,  12];
    push @mikuMidiEvents,['control_change', 0, 0, 98,  88];
    push @mikuMidiEvents,['control_change', 0, 0,  6,   0];
    push @mikuMidiEvents,['control_change', 0, 0, 98,  89];
    push @mikuMidiEvents,['control_change', 0, 0,  6,  50];
    push @mikuMidiEvents,['control_change', 0, 0, 98,  90];
    push @mikuMidiEvents,['control_change', 0, 0,  6,  50];
    push @mikuMidiEvents,['control_change', 0, 0, 98, 127];
    push @mikuMidiEvents,['control_change', 0, 0,  6, 127];
  }
  push @mikuMidiEvents,['end_track' , $pitch+1920];
  push @myEventListSection, sprintf("%d=EOS",$i*$pitch+7620);
#
#  ミク発音用メタデータのセクションを結合する
#
  my $my_miku_phonetics="";
  my $phonetic = "";
  foreach $phonetic (@myCommonSection) {
    $my_miku_phonetics = $my_miku_phonetics.$phonetic."\n";
  }
  foreach $phonetic (@myMasterSection) {
    $my_miku_phonetics = $my_miku_phonetics.$phonetic."\n";
  }
  foreach $phonetic (@myMixerSection) {
    $my_miku_phonetics = $my_miku_phonetics.$phonetic."\n";
  }
  foreach $phonetic (@myEventListSection) {
    $my_miku_phonetics = $my_miku_phonetics.$phonetic."\n";
  }
  foreach $phonetic (@myIDSection) {
    $my_miku_phonetics = $my_miku_phonetics.$phonetic."\n";
  }
  foreach $phonetic (@myHandleSection) {
    $my_miku_phonetics = $my_miku_phonetics.$phonetic."\n";
  }
#
#  Voice1トラックを生成する。
#
my @voice1Events = (
  ['track_name',    0, 'Voice1'],
);
  for($i=0; $i*119<length($my_miku_phonetics); $i++) {
    push @voice1Events, ['text_event', 0,
      sprintf("DM:%04d:",$i).substr($my_miku_phonetics,$i*119,119) ];
  }
  my $mikuMidi = "";
  foreach $mikuMidi (@mikuMidiEvents) {
    push @voice1Events,$mikuMidi;
  }
#
# マスタートラックとVoice1トラックからVSQファイルを生成する。
#
  my $master_track = MIDI::Track->new({ 'events' => \@masterEvents });
  my $voice1_track = MIDI::Track->new({ 'events' => \@voice1Events });
  my $opus = MIDI::Opus->new(
    { 'format' => 1, 'ticks' => 480, 'tracks' => [ $master_track, $voice1_track ] } );
  $opus->write_to_file( $myVsqFile );
}

|

« CVシリーズ Vocal CD Volume 01 星のカケラ | トップページ | melody...3D PV ver1.50 »

初音ミク」カテゴリの記事

コメント

コメントを書く



(ウェブ上には掲載しません)




トラックバック

この記事のトラックバックURL:
http://app.cocolog-nifty.com/t/trackback/110295/17374347

この記事へのトラックバック一覧です: 初音ミクに喋らせてみた(Perl版004):

« CVシリーズ Vocal CD Volume 01 星のカケラ | トップページ | melody...3D PV ver1.50 »