XML、PHP、Festival を使って 60 秒のラジオ・シアターを制作する

コンピューターで生成した音声を使って最小限のオーディオ・アートを作成する

XML、PHP、Festival を使って 60 秒シアターの音声劇を制作して録音しましょう。また動的に割り当てられた Festival の音声をキャストとして利用し、演出を行い、音響効果を入れ、台詞の流れをコントロールしましょう。

Colin Beckingham, Writer and Researcher, Freelance

Colin Beckingham はカナダのオンタリオ州東部に住むフリーランスの研究者であり、ライターであり、プログラマーでもあります。キングストンの Queen's University で学位を取得している彼は、園芸、競馬、教育、行政サービス、小売業、旅行/観光業などにも関わってきました。彼はデータベース・アプリケーションの作成者であり、数え切れないほどの新聞記事や雑誌記事、オンライン記事を執筆しており、また Linux でのオープンソース・プログラミングや VoIP、音声制御アプリケーションも研究しています。



2010年 6月 15日

60 秒シアターとは何か

皆さんは、約 60 秒のストーリーを作成することができます。基本となるシチュエーションを設定し、何らかの問題を発生させ、素早く場面を展開し、最後は何らかの方法で問題を解決し、すべてが丸く収まって終了します。音響効果には、録音された音声を使うことができます。ここでは、TTS (Text-To-Speech: 音声合成) エンジンである Festival による合成音声を使用しており、発声に抑揚がなく、感情がこもっていないため、何て言っているのか聞き取りにくい場合があります。それは音声が完全ではないためです。

音声劇の完全なサンプルとして .ogg 形式の音声ファイルをダウンロードしてください。そしてこの記事を読み進めながら、その音声劇がどのように生成されたのかを学んでください。シェイクスピアは詩人として傑出した地位を失うことはまったく気にしていませんでしたが、この記事で重要なのは劇そのものではなく、劇をどうプログラミングするかです。私はこの劇全体を、無料のオープンソース・ソフトウェアを使って生成しました。そしてこの劇には、Festival TTS エンジンと、Festival が提供している特徴的な音声を使用しています。


劇を再生する

この劇の再生には、劇そのものを含む XML データ・ファイル、そして PHP によるプロデューサー・スクリプト・ファイルの 2 つを使います。XML データには、キャスト・リスト、タイトルとクレジット、音響効果に使用するファイルのリスト、登場人物の台詞が含まれています。プロデューサー・スクリプトは XML データに含まれる命令に従って劇を再生し、オーディオ機器に出力します。この方法であれば、別の劇を作成したり現在の劇を編集したりすることも容易にでき、それらの劇を同じプロデューサー・スクリプトを使って容易に再生することができます。


劇の基本的な構造

この劇にはいくつかの幕があり、それぞれの幕はシーンで構成されています。各シーンはさまざまなイベントの連なり (音響効果、音楽、会話、長台詞など) で構成されています。実際の劇場では、幕の最初に幕が上がって最後に幕が下りるのを見ることができ、幕が下りると舞台係は次の舞台のために舞台装置の変更作業を行います。幕があることで劇をいくつかの部分に分けることができ、また多くの場合、時間が経過したことや別の場所に移ったことを幕によって表現することができます。

音声劇では、幕が開いても実際の劇場のように視覚効果を得ることはできないため、音響効果や人間が話す言葉で劇を構成しなければなりません。

音響効果を入れることで、幕が上がったことや幕が下りたことを表現することができ、耳から聞こえる目印にすることができます。また、劇のタイトルや脚本家の名前を読み上げることや、幕の最初で「第 1 幕、フォーラムの階段で」といった説明を挿入し、劇の最後ではクレジットを読み上げ、聴き手に必要と思われる何らかの説明を加えることもできます (例えば「実際の Joe Blow は 70 年間投獄され・・・」など)。また場合によると、劇の間に注釈が必要な場合があります。例えば平手打ちの音を聞いた時、2 人の役者だけがその場面にいるようであれば、誰が誰を平手打ちしたのかが、わかった方が助けになります。


登場人物: キャスト・リスト

登場人物をあまり多くすることはできません。そうでないと、1 分程度ではそれぞれの登場人物はほとんど何も言うことができません。Festival には、9 種類の異なる声による基本セットが用意されています (何人かの男性、何人かの女性、何人かの年寄り、何人かの若者、など)。そこで、登場人物を 9 人に制限しましょう。例えば、この劇には Fred の役があり、Festival の音声 voice_don_diphone (Festival の音声の詳細については「参考文献」を参照) を使って Fred を表現することにします。Fred を宣言するためには以下のようにします。

<role voice="voice_rab_diphone">Fred</role>

ここで、role (役) は Fred であり、voice (声) は XML 要素 role の属性です。この劇の中で Fred が指定されるたびに、プロデューサー・スクリプトは、Fred の台詞を話す時にどの声を使えばよいのかを認識します。Fred 用に別の声を使うことにした場合には、単に 1 ヶ所で属性を変更すればよいだけです。


ナレーターを割り当てる

ナレーターは特別で重要な人物です。ナレーターの声で、劇のタイトルと脚本家の名前が読み上げられ、解説が挿入され、最後にエンド・クレジットが読み上げられます。そのため、劇の大部分はナレーターの声によって 1 つのまとまったものになります。キャスト・リストの中でナレーターを宣言するためには、以下のようにします。

<role voice="voice_don_diphone">Narrator</role>

こうすることで、ナレーターが何かを言う際に、プロデューサー・スクリプトは Fred 以外の声を使います。


音響効果および台詞によるイベント

劇はイベントの連続です。イベントが起こるたびに、コンテキストは明確になったり複雑になったりします。以下に示すのは、2 つの連続したイベントの例です。音響効果があり、そのすぐ後に、ある人物の台詞が続いています。

<event type="effect" player="mplayer">gunshot.wav</event>
<event type="dialogue" player="Bozo">Freeze, turkey</event>

最初のイベントには effect 属性があります。effect 属性は、このイベントが音響効果であり、TTS エンジンを使用しないことを示しています。2 番目の属性は、その音響効果 (gunshot.wav ファイル) を Mplayer によって再生するように指定しています。

2 番目のイベントは、Bozo という人物の台詞「Freeze, turkey (止まれ、馬鹿野郎)」です。このコンテキストには TTS エンジンが 1 つしかないため、使用するエンジンを指定するための属性はありません。プロデューサー・スクリプトは常に同じ TTS エンジンを使用します。

この構造では、XML 要素としてのイベントはシーン内部にしかありません。ただし幕やシーンの外部で音響効果を利用したり、音声を出したりすることは可能です (例えばナレーターによる開始アナウンスや、エンド・クレジット、拍手など)。


幕とシーン

劇にはいくつかの幕があり、それぞれの幕はシーンで構成されるため、基本的なフロー構造はリスト 1 のようなものになります。

リスト 1. 幕とシーン、そして関連付けされたイベント
<act>
  <curtainUp>KDE_Window_Shade_Up.ogg</curtainUp>
  <scene>
    <event type="dialogue" player="five">...</event>
    <event type="dialogue" player="nine">...</event>
  </scene>
  <scene>
    <event type="dialogue" player="five">...</event>
    <event type="dialogue" player="two">...</event>
  </scene>
  <curtainDown>KDE_Window_Shade_Down.ogg</curtainDown>
</act>

この場合には、2 つのシーンで構成される 1 幕しかなく、各シーンには 2 行の台詞があり、そこに人物 5、9、2 が登場します。各人物には上述のようにそれぞれに固有の声がキャスト・リストに定義されています。またここでは、(幕の最初と最後に再生される) 開幕と閉幕の音響効果がファイルで指定されています。この例では KDE (K Desktop Environment) のシステム・サウンドをいくつか使用しています。


動的に音声を割り当てる

スピーカーやヘッドホンを通じて人物の台詞を伝えるのは、プロデューサー・スクリプトの仕事です。プロデューサー・スクリプトの PHP コードには、リスト 2 に示す関数が含まれています。

リスト 2. 動的に音声を呼び出す
function deliver($phrase,$voice) {
  exec('festival -b \'(begin ('.$voice.') 
         (SayText "'.$phrase.'"))\' >/dev/null',$out);
}

この関数の引数は、phrase (発声すべき内容) と voice (Festival のどの声を使って発声するか) です。exec 関数はバッチ・モードで Festival を呼び出し、voice の設定と、指定された voice を使って phrase を発声する、という2 つのことをします。begin 命令は Festival に対し、実行対象が複数あることを伝えます。


劇を完成させる

リスト 3 は、単純ながら完全な劇のデータ・ファイルの例を XML で表現したものです。

リスト 3. 完全な劇としてのデータを XML で表現したもの
<?xml version="1.0" encoding='UTF-8'?>
<play>
  <dramatisp>
    <role voice="voice_don_diphone">muchi</role>
    <role voice="voice_kal_diphone">dad</role>
    <role voice="voice_rab_diphone">narra</role>
    <role voice="voice_nitech_us_awb_arctic_hts">mscot</role>
    <role voice="voice_nitech_us_bdl_arctic_hts">spare</role>
    <role voice="voice_nitech_us_clb_arctic_hts">matron</role>
    <role voice="voice_nitech_us_jmk_arctic_hts">fuzzy</role>
    <role voice="voice_nitech_us_rms_arctic_hts">uncle</role>
    <role voice="voice_nitech_us_slt_arctic_hts">filly</role>
  </dramatisp>
  <intro>
    <music>chimes.ogg</music>
    <theatre>Sixty second theatre with XML and Festival</theatre>
    <title>Todays play - The demonstration effect</title>
  </intro>
  <act>
    <curtainUp>KDE_Window_Shade_Up.ogg</curtainUp>
    <scene>
      <!-- event type="effect" player="mplayer">tmp.wav</event -->
      <event type="dialogue" player="dad">The doctor is taking a long time</event>
      <event type="dialogue" player="matron">Yes but it is worth the wait</event>
      <event type="dialogue" player="dad">Looks like you broke your arm</event>
      <event type="dialogue" player="dad">Did you have a bad fall</event>
      <event type="dialogue" player="matron">Yes one of those silly falls</event>
      <event type="dialogue" player="matron">Icy steps</event>
      <event type="dialogue" player="dad">Could happen to anybody</event>
    </scene>
    <curtainDown>KDE_Window_Shade_Down.ogg</curtainDown>
  </act>
  <act>
    <curtainUp>KDE_Window_Shade_Up.ogg</curtainUp>
    <scene>
      <!-- event type="effect" player="mplayer">tmp.wav</event -->
      <event type="dialogue" player="dad">It is really cold out there</event>
      <event type="dialogue" player="uncle">Yes the cold gives me chill blains</event>
      <event type="dialogue" player="dad">Hands or feet</event>
      <event type="dialogue" player="uncle">Both</event>
      <event type="dialogue" player="dad">That is bad luck</event>
    </scene>
    <curtainDown>KDE_Window_Shade_Down.ogg</curtainDown>
  </act>
  <act>
    <curtainUp>KDE_Window_Shade_Up.ogg</curtainUp>
    <scene>
      <!--event type="effect" player="mplayer">tmp.wav</event -->
      <event type="dialogue" player="dad">Thats a bad cough</event>
      <event type="dialogue" player="filly">Yes it hurts when I breathe</event>
      <event type="dialogue" player="dad">I am sorry to hear that</event>
      <event type="dialogue" player="filly">What is your ailment</event>
      <event type="dialogue" player="dad">Oh I am not actually sick</event>
      <event type="dialogue" player="dad">But I do not feel well unless I surround
            myself with people who are a lot worse off</event>
    </scene>
    <curtainDown>KDE_Window_Shade_Down.ogg</curtainDown>
  </act>
  <end>
    <musicEnd></musicEnd>
    <credits>Thanks to Festival, PHP, Audacity and XML</credits>
  </end>
  <Applause></Applause>
</play>

この XML データ・ファイルでは、ルート要素は <play> です。この劇では、データ・ファイルの中央付近に <act> (幕) と <scene> (シーン) がある他、開始部分で配役と各配役の声が <dramatisp> 要素の中で宣言され、<intro> セクションでナレーターまたはアナウンサーが劇のタイトルを読み上げ、<end> セクションには音楽とクレジット、そして大抵は <Applause> (拍手) があります。


プロデューサー

いくつかの詳細部分を別にすると、この劇を再生するために必要なすべての部分が揃いました。プロデューサー・スクリプトは、<intro> (導入部)、<act> (幕)、<scene> (シーン)、<end> (終了部) に対して繰り返し処理を行い、イベントを順次、必要に応じて Mplayer または Festival を使って再生します。リスト 4 はプロデューサー・スクリプトの全体を示しています。このスクリプトはコマンドラインから実行できるようにプログラムされています。

リスト 4. PHP で記述されたプロデューサー・スクリプト
<?php
// sixty second theatre player
echo "60 second theater player\n";
if ($argc < 2) die("No play specified\n");
$playxml = $argv[1];
$xml = simplexml_load_file($playxml);
// load players' voices
$roles = $xml->dramatisp->role;
foreach ($roles as $rolevoice) {
  $rolev["$rolevoice"] = $rolevoice['voice'];
}
$announcer = $rolev["narra"];
$timestart = time();
//
// now the introduction
//
play_effect($xml->intro->music,"mplayer");
deliver((string) $xml->intro->theatre,$announcer);
deliver((string) $xml->intro->title,$announcer);
//
// now the acts
//
$anum = 0;
$snum = 0;
foreach ($xml->act as $A) {
  $anum++;
  deliver("Act $anum",$announcer);
  play_effect($A->curtainUp,"mplayer");
  foreach ($A->scene as $s) {
    $snum++;
    //deliver("Scene $snum",$announcer);
    play_effect("chimes1.ogg","mplayer");
    $events = $s->event;
    foreach ($events as $e) {
      switch ($e['type']) {
            case "effect":
              $engine = $e['player'];
              play_effect($e,$engine);
              break;
            case "dialogue":
              $plyr = $e['player'];
              // echo "Trying $e with $plyr\n";
              deliver($e,$rolev["$plyr"]);
              break;
            default:
              die("Invalid type");
              break;
      }
    }
  }
  play_effect($A->curtainDown,"mplayer");
  $snum = 0;
  }
//
// end of the play
//
deliver($xml->end->credits,$announcer);
$timeend = time();
$length = $timeend - $timestart;
echo("Total length is $length seconds.\n");
//
// functions
//
function play_effect($effect,$engine) {
exec("$engine $effect",$out);
}
function deliver($phrase,$voice) {
  // echo "$phrase with $voice\n";
  exec('festival -b \'(begin ('.$voice.') 
            (SayText "'.$phrase.'"))\' >/dev/null',$out);
}
?>

このプロデューサー・ファイルでは、最初に劇をメモリーにロードし (この詳細は myplay.xml という XML データ・ファイルに指定されています)、その劇を XML オブジェクトとして宣言します。次に、キャスト・リストを探し、そのリストと各配役が使用する音声を配列の中にロードします。その後、ナレーターまたはアナウンサーが使用する音声を選択し、開始時刻を記録して劇の終了時に劇の再生時間がわかるようにします。劇のタイトルが読み上げられると即座に、(劇の中の幕数にかかわらず) 幕を順次再生するループに入ります。そして各幕の中では、シーンに含まれるイベント命令に従って各シーンをループ処理していきます。


最初のリハーサル

この劇を再生してスピーカーに出力するためには、以下のようにデータ・ファイルを指定してプロデューサーを起動します。

$ php producer.php myplay.xml

また、プロデューサーによって出力を録音先のファイルにパイプすれば、この劇を録音することもできます。

$ php producer.php myplay.xml | arecord (options) myplay.wav

さらには、このファイルを Audacity® (「参考文献」のリンクを参照) などのオーディオ・エディターを使って編集することもでき、あるいは sox などのオーディオ・ユーティリティーを使って操作することもできます。


改善する

このままの状態でも、録音された劇を聞くことはできますが、この手順による出力には以下の点で改善の余地があります。

  • 一部の台詞をフェードインまたはフェードアウトしたり、あるいは台詞にサウンドを重ねたりした方が有効かもしれません。このプロデューサーでは、そうしたことを劇の進行中に直接行うことはできませんが、Audacity などのツールを使ってポスト・プロダクションを行うことができます。ただし、この方法で劇を改善すればするほど、劇は最小限のものではなくなってしまいます。
  • 処理能力の低いコンピューターでは、音声エンジンの起動や停止に 1 秒か 2 秒かかる可能性があります。そのため、出力されるイベント間に不必要に長い沈黙が生じる可能性があります。こうした長い沈黙は後編集を行う際に便利です。沈黙により、イベント間の区切りが明確にわかるからです。しかし最終版では沈黙を短縮した方が、最終的な作品のテンポを改善することができます。そのためには Audacity の Truncate silence エフェクトを使うことができます。こうした方法ですべての沈黙を同様に短縮すると、劇中に挿入された、脚本上の「間」(意図的な沈黙) まで削除されてしまうことに注意してください。そのため、そうした「間」の挿入は、このプロセスの後に行うのが最善の方法す。
  • 音響効果はどんなものでも使用することができ、音声もさまざまなものが用意されていますが、60 秒という短時間では、あまり複雑にはしない方が無難です。例えば救急車のサイレンや拳銃の発砲音など、よく知られているものを使った方が有効です。こうした音響効果には非常に多くの意味合いを含めることができるからです。

まとめ

もちろん、XML による手法の代わりに、リレーショナル・データベースを使って劇や劇のイベントを保存することもできます。しかし劇や劇のイベントを保存する場合には、フラット・ファイル形式である XML を使用した方が、読み取るのにも編集するのにも遥かに作業が簡潔になります。ある台詞の発声の仕方に満足できない場合には、素早く編集してプロデューサー・スクリプトを再度実行し、新しい作品の最終版を即座に得ることができます。

発声に抑揚がなく、感情がこもっていない合成音声による 60 秒シアターでは、こうした最小限主義の芸術を実現することができます。経験豊富で訓練された役者が劇を解釈して演じるわけではないため、聴き手にとっての体験は通常と異なります。聴き手は台詞の区切りや声のトーンなどの詳細を意識しなければなりません。しかし、XML と Festival または別の TTS エンジンを使うことで、「聞くに堪える」作品を制作することは可能なのです。


ダウンロード

内容ファイル名サイズ
The 60-second playwell.ogg.zip1000KB

参考文献

学ぶために

製品や技術を入手するために

議論するために

コメント

developerWorks: サイン・イン

必須フィールドは(*)で示されます。


IBM ID が必要ですか?
IBM IDをお忘れですか?


パスワードをお忘れですか?
パスワードの変更

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


お客様が developerWorks に初めてサインインすると、お客様のプロフィールが作成されます。会社名を非表示とする選択を行わない限り、プロフィール内の情報(名前、国/地域や会社名)は公開され、投稿するコンテンツと一緒に表示されますが、いつでもこれらの情報を更新できます。

送信されたすべての情報は安全です。

ディスプレイ・ネームを選択してください



developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

必須フィールドは(*)で示されます。

3文字から31文字の範囲で指定し

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


送信されたすべての情報は安全です。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=XML, Open source
ArticleID=500065
ArticleTitle=XML、PHP、Festival を使って 60 秒のラジオ・シアターを制作する
publish-date=06152010