拙作のテキスト読み上げツールsPeachに追加した、AVI/WAVファイル操作機能を使って、WAVファイルをハンドリングしてみたいと思います。
Olive+のスクリプトにも、AVI/WAVファイルの操作機能を追加したので、こちらも併せてご紹介します。複数のファイルをまとめて処理(バッチ処理)するようなケースでは、Olive+の方が使い易いかと思います。
今回使うのは、主にミキシング機能です。sPeachで読み上げさせたテキストを動画のナレーションなどに使用できるよう、sPeachに以下の様なAVI/WAV操作機能を追加しました。
ミキシング以外の機能は、呼び名の通りの機能ですので、sPeachのドキュメントをご覧ください。ミキシングは、使い方によって、さまざまな可能性がありますので、少し掘り下げてみます。
そもそも、ミキシングとは、どのような機能でしょうか?ミキシングとは、複数の音声データ(WAVファイル)を混合(ミキシング)して、新しい音声データを作り出す機能のことです。
混合(ミキシング)する時、それぞれの音声データの開始時間を指定することが可能です。
また、各々の音声データのレベル(≒音量)を調整したり、音が聞こえる方向を調整したりする機能(パン、PAN)も持っています。
例えば、画面右側に居る人がしゃべった音声は、ステレオの右スピーカから聞こえたり、遠くにいる人の声は小さく、近くにいる人の声は大きく聞こえたり、と言った調整で、臨場感を出すのに使います。
カメラ(ムービ)で撮影した、音声付きの動画に音楽(BGM)を追加したり、ナレーションを追加したりするのもミキシングを使って実現します。
作業手順としては、以下のようになるでしょう。
1)sPeach:AVIからWAVストリーム抽出(元の音声を抜き出す)
↓
2)sPeach:テキストを喋らせてナレーション(WAV)を作成
↓
3)sPeach:WAVミキシング(元の音声/BGM/ナレーション等をミキシング)
↓
4)sPeach:AVI(映像)+WAV(音声)統合(元の動画とミキシングした音声を統合)
では、もう少し、具体的な例をご覧に入れましょう。
よく「音速」という言葉が使われますが、どの程度のスピードか、ご存知ですか?音速は、およそ340[m/s](1秒間に340m進む)と覚えてください。気温や湿度、気圧によってもスピードは変わってくるのですが、よほど正確な計算を必要としない限り、概ね340[m/s]で足りるはずです。
よく使われるのが、雷。ピカッと光ってから、ゴロゴロと音が聞こえるまでの時間を、ストップウォッチなどで測ります。3.5s後に音が聞こえた場合、雷の発生した場所と自分が今居る地点は、340×3.5=1190m≒1.2km離れています。
夏、夜空に打ち上げられる花火にも同じ計算が使えます。夜空に花火が開いてから、音が聞こえるまでの時間で、花火と自分が居る位置の距離が計算できます。
もっと短い距離で考えてみましょう。
普段暮らしている部屋の中には、カーテンがあったり、カーペットが敷かれていたり、色々な家具が置いてあったり、と、音を吸収・散乱するものがたくさん置かれているため、あまり気にならないのですが、賃貸物件などの内覧に行った時には、部屋の中で音が反響しているのに気が付いたことはありませんか?何も物が置かれておらず、音が吸収も散乱もされずに跳ね返ってくるので、反響音が聞こえます。
ざっと計算してみましょう。
作者宅の6畳間でサイズを取ってみたところ、およそ、2.5×3.5mでした。短い方(2.5m)の壁際に立って、声を出すと、その声は対面の壁で反射して、返ってきます。
2.5mを行って返って2.5×2=5m。音速で割ると往復にかかる時間が求まり、5÷340≒0.015s。反射と進んだ距離によって、音量(レベル)は減衰しているはずなので、適切に見積もって設定します。
sPeachを起動して、「ファイルメニュー ⇒ WAVミキシング」を選択すると、空のリストが表示されます。「追加・複製」ボタンを押して、項目を追加しましょう。
まずは、発声した音声そのもの。遅れは無いので開始時間は0s、レベルもオリジナルのまま(1)とします。パンはここでは使わないので、常に0(中央から聞こえる)としておきます。「OK」ボタンで抜けます。
リストに戻ったので、もう一度「追加・複製」ボタンを押します。上で入力した項目がコピーされたので、選択して「編集」ボタンを押します。今度は、対面の壁で反射して返ってきた音声です。5mを行って返る分、およそ0.015sのディレイがありますので、開始時間を0.015sに設定、減衰分も適切に見積もってレベルを調整します。ひとまず、レベル=0.5に設定し、ミキシング結果を聞いてみて調整します。
「OK」ボタンでリストに戻ると、以下の様になっているはずです。
ここで「OK」ボタンを押すとミキシングが実行されますが、実際にミキシング結果を聞いてみて、何度か調整が必要かもしれません。その場合、一々リストを1から作り直すのは面倒ですので、「ファイルメニュー ⇒ エクスポート」で、作成したミキシングリストをファイルに出力しておくことが可能です。
出力したファイルは、「ファイルメニュー ⇒ インポート」で取り込むことができます。インポートすると、現在のリストの末尾に追加されます。ファイルはCSVファイル(半角カンマ(,)区切りのテキストファイル)となっていますので、テキストエディタなどで直接生成することも可能です(仕様など、詳しくはsPeachのドキュメントをご覧ください)。
リストのエクスポートが済んだら、「OK」ボタンを押して先に進みましょう。出力先のWAVファイル名を問いあわせてきますので、適切なファイルを指定します。ミキシングが終わると「今すぐプレイヤを起動するか」問いあわせてきますので、「はい」ボタンを押して試聴してみましょう。
ほんの少し、エコー(反響音)のかかった音になっているはずです。ただ、あんまり、元の音声との差がわからないかも?ですね……。正面の壁に対する一次反射音だけしか計算していないから、でしょうか?
さらに、この音が背後の壁で反射して、もう一度対面の壁で反射して戻ってくると、二往復で2.5×2×2=10m、340で割って0.029s。
もし、横方向(3.5m)の壁で反射して戻ってきた音も考慮するなら、3.5÷340≒0.010sと3.5×2÷340≒0.21sも追加して、以下の様なCSVファイルになります。
0,1,0,FILE001.wav
0.015,0.5,0,FILE001.wav
0.029,0.25,0,FILE001.wav
0.010,0.5,0,FILE001.wav
0.021,0.25,0,FILE001.wav
このCSVファイルでミキシングしてみると、今度はどうでしょうか?家具などが何も置かれていない部屋の中で声が反響する感じに聞こえませんか?
学校の教室など、もっと広い部屋だと、音の遅れは大きくなり、代わりに減衰によってレベルが下がります。音を発する場所を部屋の中央に移動すると、また、エコーの返ってくる距離(時間)が変わってきます。こだわる場合は、その辺りを適切にモデリングしてミキシングすることになります。
では、部屋の中で音が反響する状況を、CGで再現した動画をご覧ください。
このページの最後にリンクしたデータ(echo_room.xitr)を使って、まず、Xi-TRACEで映像(AVI)を生成しました。次にナレーション音声をsPeachに喋らせてWAVファイルを生成します(ミキシング処理含む)。最後にsPeachの「AVI(映像)+WAV(音声)統合」機能を使って、映像と音声を統合して完成したのが、上の動画です。
次は、音の聞こえる方向、パン(PAN)を制御してみます。皆さんが普段聞いている音楽は、「右の方から○○楽器の音、左の方から××楽器の音、中央からボーカルの歌声」と言ったように、左右に広がりのある音になっていると思います。
このような音の聞こえる方向を制御するのがパン(PAN)です。前節「エコー」では、中央から聞こえる様にミキシングしたので、パン(PAN)は未使用(PAN=0、中央設定)としていました。PAN値は-1〜1の値を取り、-1だと完全に左のスピーカからだけ聞こえ、+1だと完全に右のスピーカからだけ聞こえるようになります。
PAN=0だと、左のスピーカと右のスピーカから同じ音量で再生され、結果として中央から聞こえるようになります。-0.5や+0.25などと言った中間値を設定することもできます。
わかりやすい例として、「点呼」の様子をミキシングしてみます。団体行動の時に、全員そろっていることを確認するために、「イチ、ニ、サン、……」と端から叫んでいく、アレですね。ここに、九人の人がいて、横一列に並んでいます。それが、左から順に、1〜9までカウントしていく様子を再現してみましょう。
1の人は左のスピーカだけから音が聞こえるようにします(PAN=-1)。5の人が正面(中央)に居て、PAN=0。最後9の人は右のスピーカだけから音が聞こえるようにします(PAN=+1)。1〜9まで個別に発声させたデータ(WAVファイル)を用意する必要があり、かつ、9つのWAVファイルを各々異なるPAN値と開始時間でミキシングする必要があり、sPeachでも可能ですが、機械的作業で面倒なので、Olive+のスクリプトで実現してしまいます(roll_call.olv)。
まず、1〜9までの個々のWAVファイルを生成します。
// 音声データを生成する
marray rc_str:1="1", "2", "3", "4", "5", "6", "7", "8", "9";
idx=1;
while (idx≦9)
{
aviwav speak, $(rc_str#(idx)),"file_"#(idx)"_out.wav", rate=2;
idx=idx + 1;
}
sPeachのAVI/WAVファイル操作機能と同等な機能をスクリプトで実現できるよう、aviwav命令を追加しています(最新バージョンのOlive+でお使いください)。これで、機械的に、"file_1_out.wav"〜"file_9_out.wav"の9つのWAVファイルが完成します。それぞれ、「イチ」「ニ」〜「ハチ」「キュウ」と発声したWAVファイルとなっています。
Windows 7では、Windowsの音声合成機能(SAPI)日本語版がインストールされていないため、「one」「two」〜「eight」「nine」と発声されたWAVファイルになると思います。
ミキシングリスト(CSV)ファイルを生成します。sPeachのミキシング機能で、「ファイルメニュー ⇒ エクスポート/インポート」で扱ったのと同じ仕様のCSVファイルです。同じ仕様ですので、ここ(Olive+)で作ったCSVファイルをsPeachで読み込んで使うことも、逆にsPeachでエクスポートしたCSVファイルをOlive+に読ませて実行させることも可能です。
半角カンマ区切りテキストですので、Olive+のファイル操作命令で作成可能です。
// ミキシング設定ファイル(CSV)を生成する
var fout;
fopen fout,$(dir)$/$(file)"_out.csv","w";
if (fout<0)
{
// ERROR:
errmsg "CSVファイルを作成できませんでした。";
leave stop_error;
}
idx=1;
while (idx≦9)
{
fprint fout,"#,#,#,"$"$(dir)$/$(file)"_"#(idx)"_out.wav"$"$,,
0.5*(idx - 1), 2, (idx - 5)/4;
idx=idx + 1;
}
fclose fout;
注目は、最後の方にあるfprint命令で、CSVファイルへ出力している設定値です。
最初の項目は「ミキシング開始時間」ですので、「イチ」「ニ」「サン」…と読み上げる間隔(0.5s間隔としました)で少しづつ開始時間をずらしています。:0.5*(idx - 1)
2番目の項目は「レベル」ですので、通常は1(入力WAVファイルと同じ音量でミキシング)ですが、少し、音量が足りなかったので、2に設定してあります。
3番目の項目が「パン(PAN)」です。変数idxが1→9まで変化する間に、PAN値が-1→1になる様に計算してあります。:(idx - 5)/4
後は、設定ファイル(上で生成したCSVファイル)名と、出力WAVファイル名を指定してaviwav命令のmixingサブコマンドを実行するだけです。
// ミキシング
aviwav mixing, $(dir)$/$(file)"_out.wav", $(dir)$/$(file)"_out.csv";
では、点呼の様子をCGで再現した動画をご覧ください。
メインは「点呼の声が聞こえる方向」ですので、十分距離を離したステレオスピーカか、ヘッドホンなどでお聞きください。
ページの最後にリンクした、データ(roll_call.xitr)でレイトレーシングして、スクリプト(roll_call.olv)で音声データを作成し、sPeachで統合しました。
「鍵盤ハモニカで演奏する」で、MML(Music Macro Language)を使って音楽を演奏し、WAVファイルに出力するスクリプトを作成しました(mml2wav.olv)。この節では、「かえるの合唱」をWAVファイルに起こし、ミキシングして三輪唱にしてみたいと思います。
まずは、「かえるの合唱」のMMLを起こします。「か〜え〜る〜のう〜た〜が〜」ってやつです(froschgesang_mml.txt)。
スクリプト(mml2wav.olv)を実行して、MMLファイル(froschgesang_mml.txt)を読み込ませ、WAVファイルを生成します。今回は「かえる」の鳴き声っぽく、sin波ではなく、鋸波を使って音階を奏でてみます。mml2wav.olvの先頭付近にあるwav_formと言う変数に、鋸波で生成することを指示する1を設定します:var wav_form=1;
綺麗なsin波と違って、ちょっと、がさついた音色になります。
完成したWAVファイルはmml2wav_out.wavというファイル名になっています。
輪唱は、最初の人が「かえるのうたが」まで歌った後で、次の人が「かえるのうたが」と歌い始めるタイミングでしたね?……なんと言うのでしょう?2小節分?全音符2つ分です。今、mml2wav.olvの設定で、全音符の長さをlen_zen=2sに設定してあるので、全音符2つ分は、2×2=4sです。
よって、輪唱にさせるためには、4sづつ開始時間を遅らせて、ミキシングすれば良いことになります。ミキシングに必要なCSVファイルを以下の様に作りました(froschgesang.csv)。
0.000,0.50,0.00,mml2wav_out.wav
4.000,0.50,-1.00,mml2wav_out.wav
8.000,0.50,1.00,mml2wav_out.wav
このCSVファイルをsPeachの「WAVミキシング」機能からインポートしてミキシングします。
PAN値も設定してあるので、最初に中央で歌い始め、次に左側で輪唱が始まり、続いて右側が歌い始めます。当然、歌い終わるのも同じ順番で、最後に右側が歌い終わって、終了します。
では、かえるの合唱三輪唱をお聞きください。
ミキシングによる三輪唱はともかくも、(我ながら、)かえるのモデリングがひどい……。手抜きにも程があります(1^^;)。ご紹介したかったメインが、sPeachとOlive+のミキシング機能ですので、ご容赦を。
1つだけ、Xi-TRACEの機能についてもアピールしておきます。
注目は、かえるの居る位置を中心に広がった波紋です。3匹いるので、3つの波紋が広がっていますが、ちゃんと、凹凸がついたようになっていて、水面に映り込んだカエルの姿が歪んでいます。
さらに、2つの波紋が重なった部分に注目です。ちゃんと、波と波が重なって、それらしい波形になっているのがお解りになるでしょうか?
なんだか、音波の重ね合わせ→ミキシングに通じるものを感じていただけましたか?いや、まったく関係は無いのですけれどね(1^^;)。
この機能は、凹凸マッピングと言う、物体の表面に凹凸があるかのように偽装してレンダリングする機能と、さらに複数の凹凸マッピングを重ね合わせる、多重マッピングと言う機能によって、実現しています。
まず、振動点を中心として、減衰して広がっていくcos波を、輝度を高低に見立てて描画します。
// 凹凸マッピングデータを生成する。
ginit 128,512,32;
var idx;
var pc;
var ht;
idx=0;
while (idx<fhei)
{
ht=0.5*cos (idx/fhei*2*PI*10 - 2*PI*fn_ptn*fpa) + 0.5;
ht=ht*0.5^(idx/(fhei/8));
lum2pix ht,pc;
line 0,fhei - idx - 1,fwid - 1,fhei - idx - 1, pc;
// 継続
idx=idx + 1;
}
bmap wave, 0,0,fwid - 1,fhei - 1, fwid,fhei;
ここまでは普通に、1つ分の波紋(凹凸マッピング)データの生成をしているだけです。もし、多重マッピング機能を持っていなければ、話はこんなに単純ではなくて、3つの振動点(波源)を定義しておいて、それぞれが減衰cos波の波源として波を発生させると考え、各点の波高値をすべて計算してください。上のデータでは、多重マッピングを前提としていますので、そのような複雑な計算は一切必要ないわけです。
次は多重マッピングです。
bump wave1=
{
nmap wave,FR/10;
mdsk 0,0,0, 0,0,1, 0,1,0, 1,7*FR;
mreg 0,0, 0,0.9, 0,0;
};
bump wave2=
{
nmap wave,FR/10;
mdsk -4*FR,0,0, 0,0,1, 0,1,0, 1,7*FR;
mreg 0,0, 0,0.9, 0,0;
muxa 1,wave1;
};
bump wave3=
{
nmap wave,FR/10;
mdsk 4*FR,0,0, 0,0,1, 0,1,0, 1,7*FR;
mreg 0,0, 0,0.9, 0,0;
muxa 1,wave2;
};
wave1が中央のかえるの波紋、wave2が向かって左側、wave3が向かって右側です。マッピングの位置を指定する、各mdskの設定値で、中心座標のx座標値が0,-4*FR,4*FRとなっている所が位置をずらしている記述です。
muxaの設定値が多重マッピングの指定で、お尻から見ていきます。最後のwave3の中では、muxa 1,wave2;と言う設定で、wave2との多重マッピングを指定しています。そこで、wave2を見てみると、今度はmuxa 1,wave1;となっていて、wave1との多重マッピングを指定しています。最後のwave1は、ここで多重化終了なので、muxaを指定していません。
この場合、以下の様な多重マッピングが指定されたことになります。
bump wave1 = { ... muxa c1; ... };
bump wave2 = { ... muxa c2,wave1; ... };
bump wave3 = { ... muxa c3,wave2; ... };
wave3に着目すると、wave3’=c3*wave3+wave2’
wave2に着目すると、wave2’=c2*wave2+wave1’
wave1に着目すると、wave1’=c1*wave1
順次代入していくと、多重マッピング=c3*wave3+(c2*wave2+(c1*wave1))
多重する場合は、muxaの第2パラメータに、多重するマッピング名を指定します。最後のマッピング(wave1)だけは、そこで終了なので、マッピング名を指定する必要はありませんが、係数c1を指定することができ、今回の様に省略した場合は、muxa 1;と見なします。今回の例では、c3=c2=c1=1のため、以下の様に、単純に3つの波紋(凹凸マッピング)を足し算した結果となっています。
多重マッピング=wave3+wave2+wave1
つまり、波紋1つ分(減衰cos波)のマッピングデータしか作っていないのですが、その波源をずらした3つの凹凸マッピングを多重化(加算)して、まるで波が重なったように計算しているのです。これが多重マッピングと言う機能です。
今回は凹凸マッピングの多重化でしたが、色マッピングに関しても、同様な多重化が可能ですので、マッピングデータを混合することが可能です。ちなみに、今回使った加算(muxa)だけでなく、乗算(muxm)も使用可能ですので、詳しくはXi-TRACEのマニュアルをご覧ください。
多重マッピングを使わなくても、「初めから混合(多重化)したマッピングデータを用意すれば良いこと」と、言われてしまえばそれまでなのですが……。
完成したデータをリンクしておきます。
1) | エコー | echo_room.xitr |
2) | 点呼 | roll_call.olv |
roll_call.xitr | ||
3) |
かえるの合唱 |
mml2wav.olv |
froschgesang_mml.txt | ||
froschgesang.csv | ||
froschgesang.xitr |