batファイル: forループ内 で 外部 batファイルを callする

Windowsの batファイルの編集は苦行かも知れない。 やりたいことが可能であるならば、CygwinやMSYSのBashかZshを使うのが楽だと思う。(WindowsのEXEファイルなどをCygwin上で実行することは可能だ。)

発端は、「NEUTRINOで複数のmodelで歌わせたい」だ。

NEUTRINOはデフォルトで8人(?)のキャラクターで歌わせることができる。 コーラスさせるには複数のmodelに歌わせたい。

女声なら7人のキャラクターがあるので、7人分NEUTRINOを動かす必要がある。

Windows版はNEUTRINOによる処理がbatファイルで書かれているので、batファイルで7人をバッチ処理したいと考えるのが人情というものだろう。 どうせなら、主旋律とコーラスパートも7人のキャラ全部で歌わせてみたい。 とするとメロディー×キャラクターをバッチ処理することになる。

もちろん手動でもやれなくはない。まあ、そこはお好みで。 手抜きのための労力を惜しまないことは経験値を上げるのに役立つので、気分的に余裕があるならやって損はない(と思う)。

最初の関門: 配列風な格納

batをまじめに書くのは今回が初めてだ。まず「配列」風な表現を作っておく。これはキャラクターとメロディーの名称を格納するためだ。

これは割と簡単でsetを使えば良い。

set models[1]=MELLOW
set models[2]=ITAKO
set models[3]=KIRITAN
set models[4]=METAN
set models[5]=SEVEN
set models[6]=ZUNDAMON
set models[7]=ZUNKO

set songs[1]=melody_VocalMain
set songs[2]=melody_VocalChorus01
set songs[3]=melody_VocalChorus02
set songs[4]=melody_VocalChorus03

次の関門: for ループ

%%n のようなカウンタを使う。こんな感じ:

@echo off

for /l %%n in (1,1,2) do (
	for /l %%k in (1,1,3) do (
		echo %%n %%k
	)
)

実行結果はこれ:

1 1
1 2
1 3
2 1
2 2
2 3

最後の関門: callと参照

callで外部コマンドを呼び出せるが、callの後ろはコマンド・ウィンドウで入力する場合と同様に引数をとれる。 call で引数にこのbatファイル内の変数を参照したい場合は%ではなく%%で挟む必要がある。

下の例では、echoとcall したechoでそれぞれ%と%%で囲った場合を比べている:

@echo off

set models[1]=MELLOW
set models[2]=ITAKO
set models[3]=KIRITAN
set models[4]=METAN
set models[5]=SEVEN
set models[6]=ZUNDAMON
set models[7]=ZUNKO

set songs[1]=melody_VocalMain
set songs[2]=melody_VocalChorus01
set songs[3]=melody_VocalChorus02
set songs[4]=melody_VocalChorus03


for /l %%n in (1,1,2) do (
	for /l %%k in (1,1,3) do (
		echo %models[%%n]% %songs[%%k]%
		echo %%models[%%n]%% %%songs[%%k]%%
		call echo %models[%%n]% %songs[%%k]%
		call echo %%models[%%n]%% %%songs[%%k]%%
	)
)

上記を実行すると以下のようになる:

ECHO は  です。
%models[1]% %songs[1]%
ECHO は  です。
MELLOW melody_VocalMain
ECHO は  です。
%models[1]% %songs[2]%
ECHO は  です。
MELLOW melody_VocalChorus01
ECHO は  です。
%models[1]% %songs[3]%
ECHO は  です。
MELLOW melody_VocalChorus02
ECHO は  です。
%models[2]% %songs[1]%
ECHO は  です。
ITAKO melody_VocalMain
ECHO は  です。
%models[2]% %songs[2]%
ECHO は  です。
ITAKO melody_VocalChorus01
ECHO は  です。
%models[2]% %songs[3]%
ECHO は  です。
ITAKO melody_VocalChorus02

callを使う場合は%%で囲わないと正しく展開されない。

というわけで最終的には下のようなbatファイルで所望の動きになった:

@echo off

set models[1]=MELLOW
set models[2]=ITAKO
set models[3]=KIRITAN
set models[4]=METAN
set models[5]=SEVEN
set models[6]=ZUNDAMON
set models[7]=ZUNKO

set songs[1]=melody_VocalMain
set songs[2]=melody_VocalChorus01
set songs[3]=melody_VocalChorus02
set songs[4]=melody_VocalChorus03

for /l %%n in (1,1,7) do (
	for /l %%k in (1,1,4) do (
		call NEUTRINO.bat %%models[%%n]%% %%songs[%%k]%%
	)
)

ちなみにcallで呼んでいる”NEUTRINO.bat”はもともと”RUN.bat”だったものをリネームし、引数にmodelとbasenameを受け付けるようにしたもの。

変更しているのは以下の箇所だ:

set BASENAME=%2
set ModelDir=%1

下はwavファイル名を変更している箇所。BASENAMEにModelDirを加えて、キャラクターごとにwavを生成するようにししている。 (そうしておかないと、上書きされてしまう。)

echo %date% %time% : start NEUTRINO
bin\NEUTRINO.exe score\label\full\%BASENAME%.lab score\label\timing\%BASENAME%.lab output\%BASENAME%.f0 output\%BASENAME%.melspec model\%ModelDir%\ -w output\%BASENAME%.mgc output\%BASENAME%.bap -n 1 -k %StyleShift% -o %NumThreads% -d %InferenceMode% -m -t

echo %date% %time% : start WORLD
bin\WORLD.exe output\%BASENAME%.f0 output\%BASENAME%.mgc output\%BASENAME%.bap output\%BASENAME%_world_%ModelDir%.wav -f %PitchShiftWorld% -m %FormantShift% -p %SmoothPitch% -c %SmoothFormant% -b %EnhanceBreathiness% -n %NumThreads% -t