縦のカラオケは横より読みにくく、必ずしも好ましいものではないが、 アイキャンディーとしてたまには作ってみたいという要望はあるだろう。
縦カラオケの生成は自動化可能だが、とりあえず手動でやってみた。 自動的にやる方法は次のセクションで説明するが、繊細な微調整には原理の理解が必要であり、一度は手動でやってみるといいだろう。
サンプル画像(640x480)
作例ASSスクリプトとサンプル動画 (3.9 MiB)
恋するオンライン
作詞:クラムチャウダー・シベリア・アタック
作曲:秋山浩司
曲のライセンスがcc by-nc-saのため、自動的に上のサンプルも同じライセンス。
カラオケの説明用に使えるパブリックドメインのいいサンプルがないすかねぇ。。
画像を90度回転させた絵に@フォントで普通にカラオケしたら簡単なのでは? という気もするが、 ここではRTLにも適用できる一般的方法で。いずれは自動化されるべきだが、 それにはアルゴリズムを検討する必要がある。 手順としては、
トークンの時間リストはプログラム的に容易に自動化できるものだし、 Y座標を調べて個々にt-clip化しなくても、そのリストにY座標の要素を新たに追加して一括変換した方が効率的だろう。 しかしまずは勉強のため、全部手動でやってみた。
注意1: ルビなしでいいなら4ステップで完成する手順にしてある。 実際には、Y座標調べの前にルビ配置まで決定しておくほうがいい。 それですべてのルビハング(後述)が解決するわけではないが、 見通しは良くなる。
注意2: すべてのt-clipは、 最終結果のピクセル位置、場合によってはサブピクセル位置に依存し、 したがって物理フォントと、論理フォントと、レンダラーに依存する。 (1) 本例は @DHPGothic-EB (@DHP特太ゴシック体)を使っているので、フォントがないと位置が合わない。 (2) Windows XP は太字がない物理フォントの太字を論理フォントではエミュレートしてくる(品位は落ちる)ので、 太字がないフォントで太字を使うと、Windows 2000と位置が合わない。 (3) レンダラーはVSFilter2008年6月版で確認。
Dialogue: 10,0:01:23.12,0:01:43.22,tatekara,,0000,0000,0000,, {\K30}{\K115}世界の{\K50}終{\K80}わ{\K60}{\K80}りを{\K80} {\K70}待ち {\K120}草臥{\K100}れた{\K135}僕らは ;世界の 300,1450 ;終 1450,1950 ;わ 1950,2750 ;りを 3350,4150 ;待ち 4950,5650 ;草臥 5650,6850 ;れた 6850,7850 ;僕らは 7850,9200
簡単のため、トークンは大ざっぱに切り、タイミングも雑に50 ms単位。 適宜改行を入れている(以下同じ)。 リストは単純なもので、「世界の」の色変化開始がt=300、変化終了がt=1450といった意味。 「終」以下も同じ。Kの引数を足していった数値の10倍を書いているだけだからその気になれば、すぐ自動化できる。
Style: tatekaraBg,@MS UI Gothic,
27,&H00ffffff,&H01ffff00,&H00000000,&H80000000,0,0,0,0,100,100,0,-90,1,1,1,7,600,0,30,128
太字が重要な場所で、@フォントは何でもいいが、上では例としてOSの付属品を書いている。
a3rのフォントビュアー([Ctrl]+[F])では、Ignore Symbol/Vertical/Rasterのチェックを外さないと縦フォントがリストされないので注意。
位置7で左余白をたくさんとって-90度回転させることで、右上からの縦書きを実現している。
回転前には字幕のほとんどがフレームの右端を飛び越えたオフスクリーン領域にはみ出していてそれを回転させることで正しい位置に呼び出しているわけだが、
オフスクリーン領域にはみ出しそうになると一般にワードラップがかかってしまう。それを無効にするために
WrapStyle: 2
とするか、あるいは各行に {\q2}
を指定する。前者は1回指定で済むが、
一般の Dialogue と共存できなくなるので、
普通は {\q2}
を使うと良い。
縁ワイプのときはt-clipの意味までは理解しなくてもツールがやってくれたが、 縦カラはツール化してないので、t-clipを自分で書く必要がある。 作業のかなりの部分はやれば簡単に自動化できそうだが、まあ手動でやっても、 ほかの複雑なエフェクトと比べて特にしんどいものではない。 実際このサンプルは気まぐれに突然作り始めて、1時間ほどで完成した。
t-clip とは「長方形クリップ範囲を連続変化させることによる、カラオケと似た効果」のこと。 簡単にしくみを説明すると、
今「世界の」という語句が、左上隅(567,220)、右下隅(640,106) という長方形の範囲にあるとする。
このとき、{\clip(567,22,640,106)}
というASSコマンドは、この領域だけを描画し、領域外を(本来ならそこに字幕の文字があったとしても無視して)描画しない、
という意味になる(グローバルな設定ではなく、そのコマンドがついているDialogueに対する指定)。ここでもし、ボトムY座標の106を例えば56に減少させて、
{\clip(567,22,640,56)}
と書けば、56ピクセルまでしか字幕が出ないことになる。
さらに、ボトムY座標をトップY座標22と等しく{\clip(567,22,640,22)}
と書いてしまえば、選択範囲は高さ0で、
要するに何も描画されない。この「何も描画されない状態」から「世界の」だけが描画される状態へと連続変化させれば、
「世界の」が端からだんだん見えてくることになる。その変化の時間タイミングは、既に調べたように
;世界の 300,1450
であるから、
{\clip(567,22,640,22)}{\t(300,1450,\clip(567,22,640,106)}世界の終わりを 待ち草臥れた僕らは
と書けば、高さ0の何も描画しない状態で初期化してから、(567,22,640,106)へ描画範囲を空間的に移行させる意味になる。
この空間的移行は時間的にt=300で開始されt=1450で終了する(\t
コマンドになじみがないかたはass-specs.doc参照)。
空間軸と時間軸の両方をコントロールすることに注意。
これによって「世界の」のカラオケ変化をt-clipに置き換えることができた。 詳しく言えば「カラオケ変化後の色」をt-clipに置き換えたわけで、 「変化前の色」については別のレイヤーで処理する。変化前については、原理的には変化後と逆に動くt-clipで処理すればいいわけだが、 簡単には単にスタティックに出しっぱなしにして、「変化後」のレイヤーが上に出現することで結果的に隠されるようにしてしまえばいい。 本例ではそのアプローチを使う。 ただし、アルファチャンネルがからむときは、例えば半透明の文字が上に乗っても下が隠れてくれないので、 このアプローチは使えない。 アルファチャンネルを使うときは下のレイヤーも逆に動作するt-clipにてダイナミックにする必要がある。 典型的にはシャドーはアルファ0x80になっているので、注意を要する。
上の数値例では、長方形の右辺は必要以上に大きめにとってある。これは後からルビをまとめて面倒見るため。
;世界の 300,1450 ;終 1450,1950 ;わ 1950,2750 ;りを 3350,4150 ;待ち 4950,5650 ;草臥 5650,6850 ;れた 6850,7850 ;僕らは 7850,9200
以下同様に「終」「わ」「りを」などもt-clipで書き換えていくわけだが、この場合、長方形の左、右、上は一定で、
下が伸びていくだけだ。変化しない場所はコピペで済まそう。
{\t(,,\clip(567,22,640,)}
をトークンの数だけコピペする。
{\clip(567,22,640,22)}{\t(300,1450,\clip(567,22,640,106)}
{\t(,,\clip(567,22,640,)}
{\t(,,\clip(567,22,640,)}
{\t(,,\clip(567,22,640,)}
{\t(,,\clip(567,22,640,)}
{\t(,,\clip(567,22,640,)}
{\t(,,\clip(567,22,640,)}
{\t(,,\clip(567,22,640,)}
あとは、時間の引数二つとclipの第4引数だけを埋めればいい。 時間の引数はリストにあるt値をそのまま書くだけだ。問題は各トークンの下の端のY座標の取得だ。 多状態カラオケと同じアルゴリズムで自動でスキャンできるはずだが、今は手動でやる必要がある。 a3rで拡大鏡を見ながら、トークンの境界を調べよう。 文字間に余裕があるときは、空白部分のどこでもいいのだが、文字がくっついているとき、 1ピクセルでも足りないと色が変化しきらないし、1ピクセルでも超えると次のトークンまで色がはみ出るので、 慎重に。a3rで\posを取得するのは[Alt]+ClickまたはMiddleClickだが、[Tab]+Clickで裸のx yが取れるので、 これを貼り付けてから前半のxを消すと良い。 (v0.1-test32以降(v0.0.9.58 = test32+ を含む) でテストとして [Ctrl]+[Alt]+[Shift]+右クリック でY座標だけクリップボードに送るようにしてみた。)
追記: test38以降では、Options | Mouse Click メニューから選択することで修飾キーなしのクリックだけで、 「左クリック=X座標取得、右クリック=Y座標取得」にできる。
参考: t-clipと似て非なるものにt-rがある。どちらも華やかなカラオケで使われるが、 t-rは時間位置の指定だけででき、Kカラオケから容易に生成できるのに対して、 t-clipは文字の空間位置を指定する必要があるので、一般に難易度が高い。 t-rは時間軸のエフェクト、t-clipは空間軸のエフェクト。 t-rは文字単位のエフェクト、t-clipは1文字をさらに分割できるエフェクトだ。
「見えない状態からだんだん見えてくる」各行が用意できたら、XYの位置はまったく同じ場所のZ方向の下にまったく同じ文字で「最初から見えているレイヤー」を用意する。
まったく同じ文字なので、基本的には下のレイヤーは上のレイヤーに隠されて見えない。 ところが上のレイヤーは最初不可視で、だんだん出現してくるので、結果として下のレイヤーのスタイルから上のレイヤーのスタイルに徐々に切り替わるように見え、カラオケ効果が実現する。
最初から見えているレイヤーがカラオケの色変化前の状態、だんだん見えてくるレイヤーが色変化後の状態で、変化後には、 上のレイヤーが見えるようになったせいで下のレイヤーが見えなくなって、下の色が上の色で上書きされる。 2行目のクリップ領域右辺も、必要以上に大きめにしておく。 理由は同じクリップを使いまわしてルビも処理するため。というか、レイヤーを分離しているので、 全部のクリップで左辺は0、右辺はPlayResX(例えば640)にしても問題ないはず。 ここでは簡単のため上のレイヤーは影を落とさないで(全透過)影は全部下で出す。 言葉での説明は限界があるので、詳しくは実際のサンプルスクリプトと実例ビデオを参照。 前述のようにアルファがからむと一般に少し複雑になる。 本例では単純にするため、Z方向で重なる場所は完全不透明か完全透明かのどちらかにしている。
作例のフォントでは「オンライン」という文字の「ン」と「ラ」が接近しすぎていてオーバーハング気味になっている。
ちょうどトークン境界なので、「ン」の変化完了の副作用で「ラ」の頭がちょっと変化するか、
または副作用を避けるために「ン」が完全に変化しきれないか、ということになりかねない。
それを回避するため、
オン{\fsp1}ラ{\fsp0}イン
として1ピクセル水増ししてある。
「草臥れた」の漢字部分もルビ「くたび」が後からアンダーハング、オーバーハングしそうなので、
それを見越して微妙に字間をあけておいてもいいだろう(この作例ではその処理は省略)。
ここまでくれば後はルビだけ。ルビは難しくない。
いろんなやり方があるだろうが、このようなt-clipの場合、いちばん簡単なのは(手抜きともいう)、
ルビを1行で記述して、同じt-clipをコピペして済ましてしまうことだ。上記のようにアンダーハング、オーバーハングがあるとルビ部分の色変化が微妙に整合しなくなる。よってルビ部分のt-clipは微調整してベースの漢字と独立のタイミングで動かすのが本来だが、
今は単に縦カラオケの概念説明なのでそこまではやらない。
ルビを1行で記述するのは、次のようにルビとルビの間に {\fscx???} {\fscx100}
を置いて???を調整するといい。
時々 fscx を使わずにスペースを打ちまくる人がいるが、効率が悪い上にスクリプトの可読性が低下し、
おまけにスペースの整数倍でしか制御できないので繊細なポジショニングができない。
こういう場面では、小数倍が自在に使えるfscx+スペース、が定石だ。
注: トリッキーな書き方でいいなら、
{\fscx???} {\fscx}
(引数なしでデフォルト復帰)でも良い。
Style: tatekaraBgRuby,@DHPGothic-EB,18, &H00ffffff,&H01ffff00,&H00000000,&H80000000, 0,0,0,0,100,100,1,-90,1,1,0.5,7,600,0,30,128 せかい{\fscx450} {\fscx100}お{\fscx1750} {\fscx100}ま {\fscx420} {\fscx100\fsp0.5}くたび{\fsp1}{\fscx675} {\fscx100}ぼく
このスタイル例ではデフォの文字間が1で、「くたび」はきついので文字間0.5に圧縮している。ルビも2レイヤーによって、 カラオケ効果を出す。 t-clipの左右を大きめにとったのが生きて、まったく同じt-clipのシークエンスをコピペするだけで完成する。 既に注意したように、実際には、このように使いまわすと、Y方向に色変化のハングが出やすい。 親文字に対してルビの文字数が多いと時間的に拡散しすぎるし、 漢字1文字にルビ1文字なら時間的に詰まりすぎる。 サンプルは、あくまで説明のための単純化した例で、模範的な作例というわけではない。 例えば「闇」のルビ「やみ」の「や」が大きくアンダーハングしており、 色変化が少し早すぎるのが目立つので、気をつけて見てみよう。 といっても、これはハングの問題を説明するのにもいいからと放置してあるだけで、 原因になっているt-clipのY座標パラメータを若干増減する(例えば5ピクセル変える)だけで簡単に解決する。
基本的には自動化できるとしても、細部にはいろいろと手動の微調整も必要で、 そういうときには低水準でスクリプトを直接いじれることも結局役立つだろう。 ツールは便利だし必要だが、高度に自動化されたツールに頼り切ると微妙な問題を回避できなかったり、 全般に型にはまったことしかできない結果にもなる。
ルビを時間的にKタグで制御するときはこの問題は発生しない。 t-clipで空間側から制御するときで、かつ親文字のt-clipを流用するときは、次の4通りの不整合が発生しうる。
正のオーバーハングとアンダーハング: ルビが長くて終端が最後の親文字の次の文字にまでかかっている(オーバーハング)と、 親の色変化でルビが変化しきらない。 同様に長いルビは始端が親文字の前の文字にまでかかるため(アンダーハング)、親文字が変化しない前に少し変化してしまう。
負のオーバーハングとアンダーハング: 短いルビ、特に漢字1文字に対するかな1文字や、 2文字以上の漢字を短いかなで読ませる場合、例えば「都会」と書いて「まち」とルビをふる場合、 ルビの始端が親文字より遅れ、終端が親文字より早過ぎる結果になる。
基本的にはルビ側t-clipの座標調整で解決できるが、極端な例では親文字側を多少ずらして位置調整を図る必要もある。 ルビとの関係で親文字側位置を微調整するのはルビレイヤーのt-clipのY座標を調整するのよりかえって面倒だが、 必要に応じて行えば、より美しい最終結果が保証される。
ルビでない本体の文字側が相互にくっつきすぎている(オーバーハング、アンダーハング)ときはYを調整することでは回避できず、 別途処理する必要がある。 本文で述べたように、fspを使うか、または細いスペース(fscx+スペース+fscx)を挿入する。
前回は縦カラオケを手動で生成した。 今回はこのうち「リスト」を作る部分と、「リスト」+Y座標からt-clip縦カラオケを作る部分を自動化する。 トークン位置のY座標は現時点では手動で取得するが(後述)、1行1分もかからないだろう。 全般にトリッキーな要素はなく、明快な作業だ。
必要ソフト: a3r v0.1.0.0-test33で実験的に対応(テスト不十分)。AviSynth と VSFilter 必須。
まずは縦にレイアウトした通常カラオケを作る(前回参照)。このままではレイアウトは縦だが色変化は横だ。 a3r の Tools | Karaoke | Vertical Karaoke (Semiauto 1) にてこのASSを読み込むと、 filename.ass に対して、filename~vkara1.ass という名で作業用ファイルが出力される。 Y座標を取り直すのは(1行1分もかからないとはいえ)できれば避けたいので、なるべく最終的な位置が決まってから行う。 トークンの切れ目で前後の文字が重ならないように最初から調整しておこう。
入力例: ...,,{\K30}{\K115}世界の{\K50}終{\K80}わ{\K60}{\K80}りを{\K80} {\K70}待ち {\K120}草臥{\K100}れた{\K135}僕らは 出力: ;vkara; t1= 300, t2= 1450, [ 世界の ], y1= , y2= ;vkara; t1= 1450, t2= 1950, [ 終 ], y2= ;vkara; t1= 1950, t2= 2750, [ わ ], y2= ;vkara; t1= 3350, t2= 4150, [ りを ], y2= ;vkara; t1= 4150, t2= 4950, [ ], y2= ;vkara; t1= 4950, t2= 5650, [ 待ち ], y2= ;vkara; t1= 5650, t2= 6850, [ 草臥 ], y2= ;vkara; t1= 6850, t2= 7850, [ れた ], y2= ;vkara; t1= 7850, t2= 9200, [ 僕らは ], y2= ;vkara END;
出力のリストの意味は前回と同様だが、y座標の値(等号の後ろ)が空欄になっている。 さしあたって、ここは手動で埋める必要がある。
リストのy2に各語句の下端のY座標を記入する。 最初のトークンだけは、上端のY座標y1も必要になる。 ASSファイルをa3r でプレビューして、該当ポイントを [Ctrl]+[Alt]+[Shift]+右クリックすると、Y座標がクリップボードに送られるので、 貼り付ける。 このステップはまだ自動化していないので手動で行う必要があるが、1行1分もかからないだろう。
X座標、つまりclipの幅はフレーム全体(左が0、右がPlayResX)に設定される。 (ASSのヘッダでPlayResXが未指定の場合は既定値640)
~vkara1.ass にリストのY座標を手動記入したら、 Tools | Karaoke | Vertical Karaoke (Semiauto 2) にてその~vkara1.ass を読み込むと、 ~vkara2.ass として t-clip による縦カラオケが生成される。ここから先は前回と同様で、 好みに合わせて下敷きレイヤーなどを自作すればいい。
通常カラオケを作り、前回のように90度回転して縦配置にしたら、 半自動で効率的に縦カラオケ変換できることが分かった。手動操作の部分も、未実装だがやれば自動化可能だ。 多状態カラオケでは既に実装されており、技術的には、全自動化に特に困難はないだろう。 次回予定、縦カラオケのルビ処理。
vkara2を作るとき、vkara1のリストで最初のトークン以外でy1を指定しても無視される(多状態カラオケのFast modeと同様)。 この縦カラオケは、(単純縁ワイプと同じで)2色のトークンレスで実現されるからだ。 Kカラオケでは概念上「現在どの文字からどの文字までがアクティブ」というトークンの右境界と左境界(縦なら下境界と上境界)がある。 トークンの左境界から右境界へ、トークンごとに色変化が進む。 通常は左境界は意識されないがt-rを使えばそこにエフェクトの境目になる。
トークンレスというのは「どこまで色が変わったか」という一つの「前線」(カスプ)だけがあって、 トークン末尾側は特に処理しないという意味(要するに通常のKカラオケの見かけと同じ)。 多状態カラオケで Pure Tokenless オプションは左境界を使わないことを意味し、 逆にそのオプションを無効にすれば左境界を基準にセルを配置することもできる。
縦カラオケも実はトークン境界を入れて3色カラオケにすることはできる(アルゴリズム的にはまったく同じ手間)。 ただし逆に、3色、一般に3色以上の多状態のカラオケだからといって常にトークン境界を使っているわけではなく、 むしろトークン末を無視して単にカスプから等距離でセルを分割していくほうが一般に滑らかに見える。 t-clip ではトークン末を使うのも使わないのも、どちらも可能だ。
補足: 長方形領域を埋めていくことによるt-clipカラオケは、文字単位のKカラオケと完全にイコールではない。 特にオーバーハング、アンダーハングがあるとき差が目立つ。 文字単位のカラオケを完全にエミュレートするには、ハングについてはレイヤーを分けるしかないだろう。
縦カラオケのルビについて書く予定だったが、それ以前にツールにいろいろバグがあったので、 それを先に直した。 主な不具合は test33 の vkara1 で、カラオケのタグがカラオケ以外のタグを含んでいると、 おかしくなることがあったのと、小文字のkタグが時間的に正しく解釈されていなかったこと。 a3r test36で直したつもりだが、まだテスト不足。
vkara2 では下敷きレイヤー(スタティックでいい場合)を一応、自動生成。
;[Bg];Dialogue: ...
とコメントアウトされているので、使いたいときは、頭の ;[Bg]; を一括置換などで消去。ただし、
スタイルは自分で定義してください。
スタイル名は、上の乗る t-clip のレイヤーのスタイル名の末尾に Bg を付加したものになっています。例えば、入力が、
Karaoke1 というスタイルなら、Karaoke1Bg 。
縦カラオケは t-clip で実装しているので、通常のASS風カラオケも、縁ワイプも、どちらも同じ手間になる。 縁ワイプにしたいときは、例えば~Bのレイヤーのボーダーを薄くして、t-clipのボーダーを濃くそして/または太くするだけ。 縁を変えるかどうかとは別問題として、 アルファを使いたい場合は下敷きレイヤーもダイナミックにする必要があるが、それはまだ自動化してない。 ところで縦カラオケに限らず、ルビをきれいに配置するには親文字側の文字間を調整するほうがいい場合も多い(少ない漢字に長いルビが乗るような場合)。
実物大画像
作例動画と使用したASSなど (7.8 MiB)
1回目は単純化して、ルビは親文字と同じt-clipを流用したが、微妙な問題があった。 今回の第2サンプルではルビをちゃんと処理しよう。
親文字・ルビとも適宜配置を決めてから、ルビはルビで別個にvkaraを適用することで、もっと柔軟に処理できる。 vkaraツールにはBOMを二重につけるバグがあったが、実用上問題なかった。Test39 で修正済み。 修飾キーなしでクリックだけで座標が取れるモード(Options | Mouse Click | L-Button for X...)や、 デフォルトより大きい拡大鏡が右側に表示されるモード(View | Compact Mode)を設定したので、 半自動t-clipはこれでだいぶやりやすくなるだろう。Compact Mode はこういう作業では地味に便利(Test 39a以降で機能)。
カラオケをゼロから作る全過程で発生したファイルを保存しておいたので(.7zに同梱)、 参考にしてください。
001-lines.txt 歌詞のテキスト 002-timed-lines.ass 歌詞のテキストを行ごとにタイムしたもの 注: スタートタイムはぴったりに測る 003-tokens.txt 歌詞をトークンにばらしたテキスト 004-timed-tokens.ass 各トークンを1行としてタイムしたもの 注: 一般にエンドタイムは要らない(次のスタートタイムで自動的に分かる) 005-crude-karabase.ass 行タイミングとトークンタイミングを合成しただけのカラオケ 注: a3rのShift+T 006-karabase-horiz.ass タイミングを調整・確定させ水平カラオケとしたもの 注: 行をぴったりに測ったのでここでリードインとスイング アイキャンディーなのでスイング200msほど。(縦は実用向きでないが、 実用カラオケに使うならもうちょっとスイングした方がいい) 007-karabase-vert.ass スタイルを変えて垂直に配置したもの 注: 垂直にするとタイミングが分かりにくいので水平で確定させておく 008-karabase.ass ルビをつけてほぼ最終予定図にしたもの 009~VKara1.ass a3rが生成したvkara1にY座標を手動で書いたもの。 手動といっても1行30秒くらい? 010~VKara2.ass a3rが生成したvkara2(一応完成) 011~VKara1.ass 「オンライン」がつまりすぎてオーバーハングしたのでそこだけやり直し 012~VKara2.ass 改めてvkara2 013~VKara1.ass Y座標の勘違いを一つ発見してその行だけやり直し 014~VKara2.ass 改めてvkara2 015-final.ass 仕上げ
t-clipの場合、縁ワイプもそうでないのも同じ手間なので、 今回は縁ワイプにしておいた。 1行でも2行でもほとんど同じなので、大は小を兼ねるで2行の作例を示してある。