自分にとってのプログラム

AppleScriptやESTKを、映像の表現者が用いて、自家製のアプリを作る目的は、「自分の制作環境を強化する」事です。なので、

  • 必要十分な機能(=至れり尽くせりは無用)
  • 短い開発期間(=本業は映像表現)
  • 自己の環境で動作すれば良い(=誰もが使える事を目指す必要なし)

‥‥というアウトラインになります。作ったアプリを売る訳ではないので、広範な互換性は必要ないですし、エラー対策も大げさにせずに済みます。

思うに、開発で何が一番面倒かというと、互換性とエラー対策です。例えば、対応するQTのフレームレートは、今だと、23.976, 24.0, 29.97DF, 29.97NDF, 30.0でよろしいかと思いますが、QT自体はそれこそ1.0とか10とか20などのフレームレートも許容していますので(Seconds Per Frameなんて事もできる)、全部に対応しようと思ったら、それだけでかなりの時間を費やす事になります。

当座は、自分と自分のワークグループだけで動作すれば良いのですから、互換性とエラー対策は大幅にカットできて、アプリの完成までの時間を短縮できます。規模の小さいものなら、数十分〜1時間未満で出来上がる事すらあります。完成したら、即使用開始できます。

「でもさ、そういうことって、プログラムが出来る人の言い草じゃん」‥‥とか思う人もいるでしょう。

自分はスクリプトやアプリなんて作れない‥‥なんて思ってたのは、私も同じ。コンピュータのコの字も学校では学びませんでしたが、After Effectsの習得と同じ時期から、スクリプトやプログラムも独学で学び始めたのです。‥‥独学とかいうとカッコいいですが、要は虫食いで「できそうな事から始めた」のです。

マウスクリックやドラッグ&ドロップ‥‥。コンピュータの要求する動作を、自分が延々と「やらされ」続けていると、やがて疲弊が極限に達する‥‥と、コンピュータを使い始めて早々に感づきました。ゆえに、コンピュータとの「つきあいかた」を考え、その1つの手段として、「自分でプログラムを作って、コンピュータを使う」事を意識し始めたのです。「誰かが作ったプログラムを使うだけ」ではなく。

プログラムって、特別な才能を持った人が作るもんだ‥‥などと、妙な劣等感視線や先入観がありますが、そんな事は無いですネ。

才能とか素質とか言う以前に、「やるか、やらないか」です。最初っから「完璧に覚えよう」とし過ぎるんじゃ無いですかネ。多くの人は。

まずは、「これは手作業じゃやりたくないなあ」と思う事から、取り組んでみれば良いのです。虫食いで全然構わないと、私は思います。

「基本を完璧にマスターしてから」とか玉砕必至の目標を掲げるから、いつまでも身につかない‥‥のかも知れません。「基本を完璧にマスター」‥‥だなんて、学校のように「強制力」があるような環境でしか成就できないと思いますしネ。本業の片手間でやるんですから、1日中学校に通って習得するスタイルを導入しようと目論んでも、上手くいくはずが無いです。

虫食いでも、やり続けてりゃ、覚えますよ。‥‥で、やらなきゃ覚えられない。永久に。

この「今さらのAppleScript」はメインコンテンツ部分の草稿的なモノをどんどん書いているゆえ、細部の解説がおざなりですが、まずはひと通り書きおえて、推敲の段階に入ったら、細部の解説も付加していこうと考えてます。

初心の状態では呪文にしか見えないスクリプト文ですが、実は日本語や英語に比べて、遥かに簡単です。日本語で例えると、小学校3〜4年生レベルの文法だけで、「After Effectsの自動コンポ作成」アプリだって作れちゃいます。

スクリプト文では、「構成で気配や雰囲気を伝える」とか「韻を踏む」なんて必要ないですからネ。

テスト用のダミーQTファイルを自動作成

現在の現場は、静止画連番ではなくQuickTimeが主流となっているようです。今まで、限界値の低いAVIを使ってみたり、遠回りしてきたよねえ‥‥。

しかし、また連番の時代がくるかも知れませんよ。特に劇場は。‥‥QuickTimeも結構(良い意味でも悪い意味でも)枯れてきてますからネ。

さて今回は、「各種、自動処理に用いる」ダミーのQTファイルを、AppleScriptとESTKの連携で、自動作成してみようと思います。今までは、空のファイルを偽素材として生成していましたが、今回はちゃんとしたQuickTimeフォーマットの「架空カットのQTファイル」を作ります。

使うのは、FinderとAfter Effects。

After EffectsではESTK〜JavaScriptを用いて、

  • プロジェクトの作成
  • コンポジションの作成
  • ボールドとなるレイヤーの作成
  • 実映像となるレイヤーの作成
  • レンダーキューへの追加

‥‥を、AppleScriptの助けを借りながら、自動処理します。

今回も長い文なので、早速、以下に記します。

--ここから

property COMPOCOUNT : 30

set AppleScript's text item delimiters to "" --text item delimitersを初期値にリセット

tell application "Adobe After Effects CS6"
    DoScript "app.exitCode=0;"
   
    DoScript "if(app.project.renderQueue.rendering){app.exitCode=-1;}"
    if result as integer < 0 then return --もしレンダリング中なら中止
   
    DoScript "if(!app.project.close(CloseOptions.PROMPT_TO_SAVE_CHANGES)){app.exitCode=-1;}"
    if result as integer < 0 then return --もしAfter Effects上でプロジェクトが開いていて、ユーザが閉じるのを拒否した場合は、中止
   
    set res to text returned of (display dialog "カットを作る数を入力してください" with icon note default answer (COMPOCOUNT as text)) --コンポジションを作る数(100くらいまでが適当でしょうかネ)
    try
        set res to res as integer
    on error msg
        beep
        display dialog "数は半角数字のみ、200以下の数値で入力してください" with icon stop buttons {"中止"}
        return
    end try
    if res > 200 then
        beep
        display dialog "200以下の数値で入力してください.

200以上のカットが必要な場合は、プログラムを修正する必要があります." with icon stop buttons {"中止"}
        return
    end if
   
    set COMPOCOUNT to res
end tell

tell application "Finder" --レンダリング先をFinderで作ります
    set folderPath to make new folder at desktop with properties {name:"テストQT_" & (do shell script "date +%y%m%d-%H%M%S")}
    --open folderPath
    --set bounds of window 1 to {900, 20, 1600, 460}
end tell

set compoPreset to {compoWidth:1920, compoHeight:1080, fps:24, boldFrames:8, user:"ezura", renderSettingsName:"16bit-23.976fps", outputModuleName:"ProRes422(HQ)", outputPath:folderPath as Unicode text}

set title_scene to "ani_05_" --カット名のタイトルとシーン *もしアンダーバーで各要素を区切らない命名規則ですと、エクスプレッションとの兼ね合いにより、うまく動きませんのでご了承ください
set cutList to {}
set durList to {}
set contList to {}

repeat COMPOCOUNT times --コンポジションの内容物を、指定の数量で作ります
    repeat
        set cutN to 1000 + (random number from 1 to 300)
        set cutN to (characters 2 thru -1 of (cutN as text)) as text
        if title_scene & cutN is not in cutList then exit repeat
    end repeat
    set cutList to cutList & (title_scene & cutN)
    set dur to (random number from 1 to 8) * (fps of compoPreset) + (item (random number from 1 to 12) of {0, 0, 0, 2, 6, 8, 12, 12, 12, 18, 21, 22}) + (boldFrames of compoPreset)
    set durList to durList & dur
    set contList to contList & (item (random number from 1 to 4) of {"(-.-)", "(^v^)", "(*_*)", "(~_~)"})
end repeat
cutList & durList & contList

tell application "Adobe After Effects CS6"
    DoScript "var aep=app.newProject();"
   
    repeat with i from 1 to COMPOCOUNT --以下ESTK中心のスクリプトです.AppleScriptも手助けします.
        DoScript ("//各種設定を変数に書き込みます
var fps=" & fps of compoPreset & ";
var w=" & ((compoWidth of compoPreset) as Unicode text) & ";
var h=" & ((compoHeight of compoPreset) as Unicode text) & ";
var cutName='" & item i of cutList & "_t" & (random number from 1 to 3) as Unicode text) & "';
var dur=" & ((item i of durList) as Unicode text) & ";
var boldFr=" & ((boldFrames of compoPreset) as Unicode text) & ";
var dispDur=dur-boldFr;

//新規コンポジションを作ります--尺は一旦コンポを作ってから改めて適用します
var comp=aep.items.addComp(cutName,w,h,1,1,fps);
comp.duration=Math.floor(dur/fps)+currentFormatToTime(dur%fps, fps, true);

//ボールドの背景を作成します
var sldLayer=comp.layers.addSolid([0.75,0.75,0.75],'BOLD',comp.width,comp.height,comp.pixelAspect,currentFormatToTime(boldFr, fps,true));

//カット名表記--エクスプレッションを''にしてオフすると、カット名と尺の表記になります
var textLayer=comp.layers.addText(cutName+'¥r('+String(Math.floor(dispDur/fps))+'+'+((String(dispDur%fps+100)).slice(1))+')');
setTextContents(textLayer,'Arial Black',comp.height/6,[0,0,0],0,ParagraphJustification.CENTER_JUSTIFY,[comp.width/2,comp.height/20*7],¥"thisComp.name.split('_').slice(0,3).join('_');¥",[0,sldLayer.outPoint]);

//テイク番号と尺の表記--名前の都合がエクスプレッションと合わない場合は、オフにしてもよいかと
textLayer=comp.layers.addText('');
setTextContents(textLayer,'Arial Black',comp.height/9,[0,0,0],0,ParagraphJustification.CENTER_JUSTIFY,[comp.width/2,comp.height/5*2],¥"n=thisComp.name.split('_');f=timeToFrames(thisComp.duration-outPoint,fps=1/ thisComp.frameDuration,true);'¥¥rTake '+n[3].slice(1)+'¥¥r('+(Math.floor(f/fps))+'+'+(String(100+f%fps)).slice(1)+')';¥",[0,sldLayer.outPoint]);

//作業日と作業者の表示
textLayer=comp.layers.addText('" & (do shell script "date +%y.%m.%d¥¥ %H:%M:%S") & "'+'¥rby " & user of compoPreset & "');
setTextContents(textLayer,'Arial Black',comp.height/15,[0,0,0],0,ParagraphJustification.CENTER_JUSTIFY,[comp.width/2,comp.height/5*4],false,[0,sldLayer.outPoint]);

//本映像のBGベタを作成します--ランダムで色を変えています
var bgLayer=comp.layers.addSolid([" & (((random number from 3 to 9) / 10) as Unicode text) & "," & (((random number from 3 to 8) / 10) as Unicode text) & "," & (((random number from 3 to 8) / 10) as Unicode text) & "],'BOLD',comp.width,comp.height,comp.pixelAspect,comp.duration);
bgLayer.inPoint=sldLayer.outPoint;
bgLayer.outPoint=comp.duration;

//本映像の顔文字
textLayer=comp.layers.addText('" & (item i of contList) & "');
setTextContents(textLayer,'Arial Black',comp.height/2.7,[0,0,0],0,ParagraphJustification.CENTER_JUSTIFY,[comp.width/2,comp.height/5*3],false,[sldLayer.outPoint,comp.duration]);

//本映像のタイムシート&タイムコード
textLayer=comp.layers.addText('TC');
setTextContents(textLayer,'Courier',comp.height/14,[0,0,0],0,ParagraphJustification.CENTER_JUSTIFY,[comp.width/2,comp.height/6*5],¥"f=timeToFrames(t=time-inPoint,fps=1/thisComp.frameDuration,true);Math.floor(t)+'+'+String(f%fps+101).slice(1)+' | '+timeToCurrentFormat(t,fps,false,thisComp.ntscDropFrame);¥",[sldLayer.outPoint,comp.duration]);

//レンダーキューに追加します--以下の2,3行目をアクティブにすると設定したプリセットを適用するようになります
var rqItem=aep.renderQueue.items.add(comp);
//rqItem.applyTemplate('" & renderSettingsName of compoPreset & "');
//rqItem.outputModule(1).applyTemplate('" & outputModuleName of compoPreset & "');
rqItem.outputModule(1).file=File('" & outputPath of compoPreset & "'+rqItem.outputModule(1).file.name);

//テキストレイヤーの内容を操作する自作ファンクションです--もっと多機能にできると思いますが、今回はこのくらいで...
function setTextContents(_textlayer,_font,_fontsize,_fillcolor,_strokeWidth,_justification,_position,_expression,_inOutPoint){
    _cont=_textlayer.property('Source Text').value;
    _cont.resetCharStyle();
    _cont.font=_font;
    _cont.fontSize=Math.round(_fontsize);
    _cont.fillColor=_fillcolor;
    _cont.strokeWidth=_strokeWidth;
    _cont.justification=_justification;
    if(_expression){
        _textlayer.property('Source Text').expressionEnabled;
        _textlayer.property('Source Text').expression=_expression;
    }
    _textlayer.property('Source Text').setValue(_cont);
    _textlayer.position.setValue([Math.round(_position[0]),Math.round(_position[1])]);
    if(_inOutPoint){_textlayer.inPoint=_inOutPoint[0];_textlayer.outPoint=_inOutPoint[1];}
}"
       
    end repeat
   
    display dialog (COMPOCOUNT as text) & "カットのレンダリングの準備が整いました!" with icon note buttons {"OK"} default button 1 giving up after 5 --この行をコメントアウトするといちいち報告しなくなります
   
    --DoScript ("aep.renderQueue.render();") --この行をアクティブにすると自動でレンダリングがスタートします
   
end tell

--ここまで



う〜ん、ブログに書き込んでみると、なんだか長い。しかし、内容は結構、コンパクトで単純ですヨ。

この文の解説も、またいずれ。(本陣のWeb(現在準備中)で、になると思います)

AppleScriptで、「共通のコンポジット仕様」「架空のカット名」「架空の尺」「本映像に描く絵文字」を設定・生成し、After EffectsのESTKに流し込みます。構造は、ただそれだけ、です。

実際に動作中の動画は以下の通り。スクリプト作成途中のキャプチャなので、若干内容が違いますが(上記スクリプトでは作るカット数を対話式に改善してあります)、ほぼ内容は同じです。



出来上がったファイルはこんな感じです。




ボールドの8コマを足した尺で、本映像部分はランダムに顔文字と背景色を変えています。After Effectsでは一切オペレーションをせず、ダミーのカットがいくらでも生成できます。

実際に書き出したムービーは以下のような感じです。






「これが出来る‥‥と言う事は、あんな事も、こんな事も‥‥」と想像できるんじゃないでしょうか。

実際、私の作業のスタンダート(旧来方式互換での)は、シートと素材の準備が整えば、「素組み」に近い状態までは自動で処理して、カメラワークと映像処理から「人の手」で始めます。まあ、厳密には「シートファイルを作るのも人手」なんですが、そのシートファイルの解釈もスクリプトで自動処理してキーフレームに反映させています。

コンピュータが作業者の雑務を担当する事により、作業者本人は、今まで以上の作業時間を獲得でき、より一層高度な映像表現が可能となる‥‥のです。


こういう類いの自動化を聞くと反射的に「嫌悪感」を感じる人はいるかと思います。

私が思うのは、例えば、手でマウスを操作して「レンダーキューに追加」する事は、どれだけ重要か?‥‥という事です。何かその手作業の行為で、精神性でも高められるんでしょうか?

私だったら、「After Effects上での指を疲労させる行為」は、出来る限り「映像表現に使いたい」ですネ。

些末な1つ1つの雑事が、結果的に作業者・映像表現者を疲労させる。‥‥私の16年のコンピュータ映像制作での「実感」です。その「実感」から開放される手段の一つが、コンピュータによる作業の補助です。


同時に思うのは、「自動処理を導入する覚悟と度胸のある現場」は、「乱作乱造」の状態には陥りにくい‥‥という事です。自動処理を導入するには、計画性が必要です。‥‥その事だけでも、お判りですネ?

付け焼き刃的に、自動処理なんか導入できないんですヨ。実際にやってみれば解ると思うけど。

アニメ業界の乱作乱造は「ワークフローを破壊する」性質のものなので、自動処理システム自体が「まず導入が困難」です。

自動処理システムが整然と機能する「理性的」な現場は、乱作乱造には陥りにくいのです、実は。



QTの情報を取り出す(初歩)

作品制作時は、大きく2つの面のバランスで成り立っています。運用と表現。

AppleScriptで運用面を強化すると、巡り巡って、映像表現にも差が表れます。表現に割ける時間が増えるからです。

しかし、どんなに運用面を強化して、快適で鉄壁な制作現場を構築しても、それはあくまで「作品表現が豊かになる『お膳立て』が出来た」に過ぎません。理想的なワークフローを築き上げても、面白い作品を作れるか否かは、無惨な言い方ですが「作り手の映像表現の才能」次第です。

でも、ワークフローがグチャグチャだと、どんなに才能豊かな人材を集めても、ロスが大きくて、作品表現に届く前に半減してしまいます。

要は、運用と表現の両面を、磨き続けるココロが必要なわけです。

まあ、往々にして、映像表現力に自信を持つ人は運用を軽んじ、作業を回す事を重視する人は映像表現に疎くなる傾向があります。どちらに偏り過ぎてもマズいのよね‥‥と、よく自己批判します。



今回のスクリプトは、QTの扱いの基礎です。

QuickTimeムービーファイルが、どのような仕組みなのかを、AppleScriptを使って探ってみます。

AppleScriptで簡単にQTの内容を調べるには、「QuickTime Player 7」を使います。「X」じゃダメです。

QuickTime Player 7で何か適当なQTファイルを開いて、そのファイルの様子を探ります。

探り方は、以下のようなスクリプトを書いて、調べます。

tell application "QuickTime Player 7"
    properties of document 1
end tell

「document 1」とは、一番手前に表示されているムービーの事です。

すると、以下のような「ドキュメント」情報が返されます。

{video brightness adjustment:0.0, name:"f.mov", play all frames:false, current node:missing value, id:1, max time loaded:2640, resizable:normal, time:0, show detailed movie info window:false, natural dimensions:{1920, 1080}, color table:missing value, default node:missing value, show sound controls:false, show video controls:false, show movie info window:false, class:document, show hot spots:false, preferred audio balance track:missing value, fast start:false, output muted:false, poster frame time:0, href:"", pan range:{0.0, 0.0}, selection duration:0, video contrast adjustment:0.0, current chapter:missing value, sound balance:0, sound volume:256, auto quit when done:false, savable:true, pan angle:0.0, time scale:24, presentation mode:normal, bass gain:0, tilt range:{0.0, 0.0}, scale:half, treble gain:0, streaming status message:"", preferred audio gain track:missing value, playing:false, auto close when done:false, aperture:clean, auto play:false, video tint adjustment:0.0, controller type:«constant ****Quic», dimensions:{960, 540}, duration:2640, pan tilt speed:0.0, data size:389908742, field of view:0.0, play selection only:false, live stream:false, looping:false, current chapter track:{}, auto present:false, preferred rate:1.0, video color adjustment:1.0, path:"/Volumes/外付けのHDD/Render/f.mov", stored stream:false, index:1, modified:true, saveable:true, selection start:0, local playback:true, done:false, palindrome:false, current matrix:{{0.5, 0.0, 0.0}, {0.0, 0.5, 0.0}, {0.0, 0.0, 1.0}}, rate:0.0, tilt angle:0.0, language:"SystemDefault", preview:{0, 0}, streaming status code:0, presentation background color:{0, 0, 0}, selection:0, quit when done:false, close when done:false, data rate:3545923, original file:file "外付けのHDD:Render:f.mov", plugin settings:{}, display state:normal, field of view range:{0.0, 0.0}, zoom rate:0.0, load state:complete}

‥‥いっぱいありますネ。

例えば、「natural dimensions」のラベルの値を見てみると、{1920, 1080}になっています。ナチュラルディメンションとは、自然な寸法、つまりQTファイルの「素の状態の」ピクセル寸法が解るわけです。

一方、「dimensions」は、{960, 540}になっています。これはつまり、現在表示している状態のピクセル寸法です。私が1/2の大きさで表示してたので、この値になっているのですネ。

重要なのは、time scaleとdurationの項です。このドキュメントは、time scaleは「24」、durationは「2640」となっています。1秒をどのようなスケールで扱うかがtime scale、そのtime scaleに基づいてムービーの尺を表したのがdurationです。

つまり、このドキュメントの尺は「2640/24」で110秒です。今回流用したムービーファイルは、前にフリッカー参考例で出したファイルなのですが、確かに1分50秒です。After Effectsで、24.0fpsでレンダリングしたので、とても歯切れの良い簡単な数値「24」になってくれたのです。

fpsが23.976の場合は、ちょっと状況が変わってきます。「time scaleは23.976になるのでは?」と思うかも知れませんが、「time scaleは整数で扱う」事と決められているので、そうはなりません。私の手元のQTで調べたところ、

23.976fpsのtime scale → 24000

‥‥でした。ちなみに、23.976fpsのQTの1フレームのデュレーションは

duration of frame 1 of track 1 of document 1 → 1001

‥‥でした。つまり1フレームの長さが1001という設定なのです。これを計算してfpsを求めると、

「24000/1001」=23.976024

‥‥です。まあ、たしかに。末尾の「024」という端数にそこはかとない不安が残りますが、概ね‥‥。


計算しやすいように、今度は1分ジャストの23.976fpsムービーを開いて調べてみます。

23.976fpsの1分のQTファイルのdurationは、1441440でした。

これを慌てて、「duration/time scale」なんていう計算をすると、めっちゃ誤差が出ます。

1441440/24000=60.06

結果は「60.06秒」‥‥たしかに。でも現場ではあくまで60秒として扱わなければなりません。

ドロップフレームではなく、ノンドロップフレームの「ご都合」をちゃんと考慮して計算式を組み立てましょう。

こんな感じに。

duration/フレームのデュレーション/(round (time scale/フレームのデュレーション))

round」とは四捨五入の事です。今回の場合は「23.976024を四捨五入」という事ですネ。

つまり、

1441440/1001/24=60.00

で、正しいデュレーションが返ります。あくまで「ビデオ上の時間軸」の‥‥ですネ。

こんな感じで、QTから様々な情報を得て計算すると、映像制作の各場面で用いる事ができます。

しかしなあ‥‥、こういう計算をしていると、心が荒んでくるのよネ。30fpsが29.97になったいきさつ、そして、29.97のノンドロップが生まれた背景‥‥。そして、さらに23.976 (24p)や59.94 (60p)に拡大して‥‥。「29.97DF」「29.97NDF」「30.0」の3つが混在する状況って‥‥。

それらの経緯を踏まえて、今回のような「23.976と24.0の二枚舌」のスクリプトを作らなければなりません。仕方ない事とは言え‥‥ねえ。

96fpsも「どうせ」96.0fpsにはならんのでしょうね。

アソシエーションの偉いさんたち、どこかで一回、リセットしてくれませんかネ。‥‥ハードの互換性とか言ってたら、この先何百年もずっと呪いから逃れられないよ。アレな廃棄物と同じで「解決は未来の人間に任せばよい」ってか。

その場しのぎの結果オーライ。面倒な運用を延々と引きずる。‥‥プロの現場が理路整然としているのでは決して無い‥‥事の証ですネ。

怪しい尺を知らせるスクリプト

アニメの制作現場では、作画が2コマ3コマでタイミングを作る事がほとんどで、ゆえに、カットごとムービーの尺(デュレーション)の傾向は偏ってきます。‥‥というのは、前にも書いたとおりです。

例えば、「4秒19コマ」とか、「5秒23コマ」なんていう尺は、かなり変わった尺です。なので、コンポジットを担当している作業者は、「うわ〜、妙な尺だなあ」と記憶に残ります。

しかし、記憶に無いのに、「5秒23コマ」なんていう尺が存在した場合、「何かの不具合により1コマレンダリングできてない」などの「障害の可能性」が高くなります。

今はQTでレンダリングする事が多くなったので、あまり「23コマ」などの「間違った尺」は見かけなくなりましたが、連番レンダリングではたまに発生する障害です。レンダリングが中途でエラーで止まり、再スタートした際に、1コマ欠落するのです。

まずいことに、尺の間違いはラッシュチェック(カットごとのムービーを上映してスタッフでチェックする)では見つけにくく、編集さんに渡った時点で初めて「発覚」する事がほとんどです。

間違った尺のムービーを度々、編集さんに渡していると、「いい加減な仕事しやがって」と信用を失います。なので、事前に尺間違いがないか、ちゃんと検査してから渡すのがベストです。

厳密な検査は、やはり、確固としたデータベースと照合するのが必定ですが、レンダリング時の障害から発生した類いの尺間違いは、コマ数を調べるだけでも結構「見分けられ」ます。文頭で書いた、現場の慣習による「尺の定番」が存在するからです。

今回は、尺のコマ数をチェックするスクリプトを書いてみます。現場では、実際のファイルから読み出して尺のチェックするのですが、まずは、架空の尺のリストを用意して、「検査エンジン」がうまく動くかを試してみます。

スクリプトは以下。今回はちょっと長めですが、構造自体は簡素です。

--ここから

--架空のカットの尺のリストです。実際には、QTから取得したり、連番ファイル数から取得します。
set cutList to {{cutName:"#10-c101", duration:"3+0"}, {cutName:"#10-c104", duration:"5+12"}, {cutName:"#10-c106", duration:"2+6"}, {cutName:"#10-c123", duration:"1+18"}, {cutName:"#10-c125", duration:"0+5"}, {cutName:"#10-c155", duration:"2+18"}, {cutName:"#10-c158", duration:"6+21"}, {cutName:"#10-c160", duration:"8+0"}, {cutName:"#10-c161", duration:"5+23"}, {cutName:"#10-c183", duration:"3+12"}, {cutName:"#10-c200a", duration:"2+2"}, {cutName:"#10-c200b", duration:"4+1"}, {cutName:"#10-c202", duration:"3+12"}}


--警告をおこなうための仕組みをつくります
--matchNumbersは、コマ数の番号
--dialogはそのコマ数に対するコメント
--levelは危険度レベル(level 1 を最安全レベルとして、最も危険なレベルを6としました)
set lev1 to {matchNumbers:{0, 12}, dialog:"正常と思われます.", level:1}
set lev5 to {matchNumbers:{1, 5, 7, 13, 17, 19}, dialog:"少々危険なコマ数です. 念のため尺の再確認をお勧めします.", level:5}
set lev4 to {matchNumbers:{2, 4, 8, 10, 14, 16, 20, 22}, dialog:"2コマベースならあり得るコマ数です.", level:4}
set lev3 to {matchNumbers:{3, 9, 15, 21}, dialog:"3コマベースならあり得るコマ数です.", level:3}
set lev2 to {matchNumbers:{6, 18}, dialog:"2コマ3コマ共通のよくあるコマ数です.", level:2}
set lev6 to {matchNumbers:{11, 23}, dialog:"危険なコマ数です. 尺の確認を強くお勧めします.", level:6}
set levList to {lev1, lev2, lev3, lev4, lev5, lev6}

set aColors to {{0, 0, 0}, {0, 0, 10000}, {0, 20000, 0}, {0, 20000, 0}, {50000, 20000, 0}, {50000, 0, 0}} --警告色の設定です

set numberDB to {} --0から23のコマ番号に対する、危険度レベルを設定するために、まず空のリスト「numberDB」を作ります

repeat with num from 1 to 24
    set numberDB to numberDB & {num} --「numberDB」にまず1から24で埋めます
end repeat
repeat with lev in levList
    repeat with num in matchNumbers of lev
        set item (num + 1) of numberDB to level of lev --「numberDB」に危険度レベルを当てはめます
    end repeat
end repeat
--以上で「numberDB」=各コマ番号に対する危険度レベルリストが完成しました

--いよいよ、尺をチェックして結果をテキストエディットに表示します
tell application "TextEdit" to set doc to make new document --新規書類をテキストエディットで作ります
my writeTextEdit(doc, "尺の端数をチェックしてみました!" & return & return, {0, 0, 0}) --1行目のコメントを書き込みます

repeat with dur in cutList --カットリストを順々に処理します
   
    set durationInfo to my calcFrames2(duration of dur, 24) --カットリストの尺情報を尺の分析ルーチンに投げて、結果を受け取ります
    set dispFr to (characters 2 thru -1 of ((10000 + (frames of durationInfo)) as Unicode text)) as Unicode text --フレーム総数を4ケタ表示にします(テキストエディット上できれいに表示させるため)
    set basicText to cutName of dur & tab & (displayText of durationInfo) & tab & dispFr & tab --書き込む基本情報を生成します
   
    if frames of durationInfo < 12 then --もし尺が12コマ未満だった場合
        my writeTextEdit(doc, basicText & "尺が短過ぎるかも知れません. 念のため尺の再確認をお勧めします." & return, item 6 of aColors) --‥‥のように書き込みます。警告色は「item 6 of aColors」〜つまり最危険度の色です
    else
        set myLevel to item ((framesCount of durationInfo) + 1) of numberDB --コマ番号を「numberDB」に照らし合わせて、当該の危険度レベルを得ます
        my writeTextEdit(doc, basicText & (dialog of item myLevel of levList) & return, item myLevel of aColors) --危険度別のコメントを書き込みます。テキスト色も危険度レベルに合わせた色にします。
    end if
   
end repeat

tell application "TextEdit"
    set bounds of window 1 to {20, 20, 720, 520} --最前面のウィンドウ(つまり結果を書き込んだ書類)のウィンドウ位置と大きさを見やすいように調整します
    activate --テキストエディットを最前面に表示します
end tell
--テキストエディットの表示を確認してください
--以上でメイン部分は終了です。


on calcFrames2(_durText, _fps) --前回使ったルーチンを使い回しています
    set delim to AppleScript's text item delimiters
    set AppleScript's text item delimiters to "+" as Unicode text
    set textitems to text items of (_durText as Unicode text)
    set AppleScript's text item delimiters to delim
   
    if length of textitems > 5 then return false
   
    set timescale to {1, _fps, _fps * 60, _fps * 60 * 60, _fps * 60 * 60 * _fps}
   
    set fc to 0
    repeat with i from 1 to length of textitems
        set textitem to item -i of textitems
        try
            set fc to fc + (textitem as integer) * (item i of timescale)
        on error
            return false
        end try
    end repeat
   
    set arr to {}
    set modfc to fc
    repeat with i from 1 to ((length of timescale) - 1)
        set arr to arr & modfc div (item -i of timescale)
        set modfc to modfc mod (item -i of timescale)
    end repeat
   
    set sec to (fc div (item 2 of timescale)) as Unicode text
    set frDisp to (characters 2 thru -1 of ((100 + modfc) as text)) as Unicode text
   
    return {frames:fc, durationText:(sec & "+" & (modfc as text)) as Unicode text, displayText:("(" & sec & "+" & frDisp & ")") as Unicode text, daysCount:item 1 of arr, hoursCount:item 2 of arr, minutesCount:item 3 of arr, secondsCount:item 4 of arr, framesCount:modfc, secondsText:sec, framesText:frDisp, fps:_fps}
end calcFrames2


--テキストエディットに文字を書き込むルーチンです
on writeTextEdit(_doc, _text, _color)
    tell application "TextEdit" to make new paragraph at the end of _doc with data _text with properties {font:"HiraKakuProN-W3", color:_color, size:14}
end writeTextEdit

--ここまで


AppleScript初心の場合は、読み切れないかも知れませんが、詳細な解説はいずれ。


上記スクリプトを実行すると、以下のような検査結果がテキストエディットを用いて表示されます。危険度が増すほどに、テキスト色が赤に近づいていきます。




架空ではなく、本番の作業では、上記のようには色とりどりにはならないでしょう。大体、黒か緑の文字で埋まるはずです。その中にあって、たまに赤い文字が1行あると、その行だけが異様に目立って、ユーザ(例えば撮影監督)に知らせてくれます。

コンピュータはあくまで「判断をユーザに求めてくる」だけです。意図された「5+23」なのか、意図しない「5+23」なのかは、人間が判断します。タイムシートが「5+23」だったら、「うん、そうなんだよ。中途半端な尺なんだよなぁ」と自分の中で念押しできます。

スクリプトのプログラム文を読むと、コマ番号に対する危険度レベルとコメントを設定しているのが解ります。その「からくり」通りに、スクリプトは尺を判断し、テキストエディットでユーザに告知します。

これは、「作業の内容」や「作業の慣習」をもとに、当該の様々な「値」を、プログラムで処理して判断する、初歩的なスクリプトです。こうした事をどんどん積み重ねていけば、コンピュータは、まるで介護犬のように、ユーザに色々と「尽くして」くれる存在になります。

少なくとも、私はこのようなプログラムを作業に取り入れたおかげで、格段にミスを減らし、格段に「映像表現に専心」できるようになりました。

映像作りは1枚絵を描くのに比べて、煩雑で事務的な作業が多過ぎます。‥‥で、それは減らせません。必要な雑務なのです。だったら、その雑務を「どう処理するか」を考えれば良いのです。

映像を作りたいのなら、思いのままに映像を作れるよう、環境を整えるのが「当たり前の事」です。雑務に自分の時間を搾取されっぱなしに放置しておくと、いつまでたっても本腰を入れて取り組めないのですヨ。

テキストエディットを操作してみる

少人数で映像制作をしていると、手弁当で各自が適宜制作管理して‥‥なんて考えがちですが、全くのナンセンス、「やるべき事」と真逆の行動です。少人数グループは、制作進行と呼ばれる制作を管理するスタッフが立てられない事が多いので、実は一番、その「制作」部分が甘くなり脆弱になるのです。そして、その甘さはまんま、映像のクオリティに影響します。

少人数制作ほど「誰も制作を管理していない」状況に陥り、土壇場になって「あれがない」「これが抜けてた」などの醜態をさらす事になります。プロ集団が「制作スタッフ」と呼ばれる人員を配置するのは、ちゃんと大きな意味があるのです。

私は2〜3人で作業する事がありますが、「人数が少なくて小回りが利く」のは確かにそうですが、代償として「誰も面倒を見てくれない」状況が待っています。なので、私が編み出したのが「コンピュータに面倒を見てもらう」制作手法です。まだ不完全なシステムではありますが、コンピュータに管理を委任するようになって、何よりもまず随分楽になりましたし、ミスも大幅に減りましたし、精神的にも余裕が出るようになりました。

コンピュータによる創作サポート体勢が必要なのは、まずは個人、少数人数の制作規模なのです。世間では全く逆に考えられていますが、ネ。

制作システムって、大所帯の会社が導入するものだとタカを括っていませんか。大所帯の会社は、いざとなればマンパワーでこなせますが、少人数・個人のマンパワーは悲劇的とすら表現できます。制作システムの「守護」が必要なのは、むしろ、個人や少人数なんですヨ。

ちなみに‥‥コンピュータを制作上の強い後ろ盾にする‥‥わけですから、その制作システムが「日々、何でもかんでも、いちいち手で入力しないとうまく動かない」ようでは「本末転倒」も甚だしいです。作業の中にとけ込むようなシステムでなければなりません。

現在のコンビニ・スーパーのレジをイメージすると、どういう事か、想像できるんじゃないでしょうか。面倒な作業を肩代わりしてくれるツールが、実はデータベースなどと連携して強いシステムをどんどん作っていく‥‥というのが、好ましいのです。制作システムにこき使われるようじゃアウトです。

実は、この「今さらAppleScript」は、各個人が自分なりの作業システムを作るためのきっかけになればと想い、書き綴っているのです。‥‥まあ、ちょっと遠い気もしますが、ちまたには、あまりにも文献が少ないからネ。

今回は手短に、MacOSX付属の「テキストエディット」のスクリプトをちょい、紹介します。

コンピュータが処理している様子は、人間からはまったく伺い知る事はできません。空冷ファンの音が大きくなると、「あ、大変なんだ」とか解る程度です。なので、スクリプトプログラムの文中に「見ている人間がわかるように、文字を表示する」仕掛けを作るのが一般的です。

AppleScriptで文字を表示する手段は、いくつもありますが、今回はテキストエディットを使って、遊んでみます。

以下がスクリプト文です。

--ここから

set cont to "=>
==>
-==>
- - ==>
   - - ==>
       - - ==>
      .       - - ==>
   .              .   - - ==>
             .           .    - - ==>
          .           .         .   .   - - ==>
  .            .       .           .            .   - - ==>
                  .         .                                      - - ==>
         .                          .        .       .                             - - ==>
                                 .                          .        .       .                             - - ==>
  .        .               .   .      .             .            .
.     .           .      .        .        .     .
    .           .      .     .     .
.         .    . 
.    .
"

set AppleScript's text item delimiters to "
"
set cont to text items of cont
set AppleScript's text item delimiters to ""

tell application "TextEdit"
    --activate
    set doc to make new document at the end
    set bounds of window 1 to {60, 60, 1060, 260}
    tell doc
        make new paragraph at the end of it with data item 1 of cont with properties {font:"Courier-Bold", color:{40000, 0, 0}, size:14}
        delay 2
        repeat with txt in cont
            delay 0.1
            set paragraph 1 of it to txt
        end repeat 
    end tell
end tell

--ここまで


上記スクリプトを動かすと、以下のYouTubeムービーのようになります。




‥‥まあ、これ自体に有用性はありません。しかし、文字を書き換えて動かす段取りはわかるかと思います。

次に紹介する予定の、尺のコマ数をチェックして「怪しいかどうかを告知する」スクリプトでも、テキストエディットを使います。

ではまた。

尺とフレーム数、全部入り

前回書いた「尺からフレーム数への変換」は、実際に使ってみると実用性に乏しい事がわかります。制作作業では、フレーム数から尺への変換が必要な場合もありますし、After Effectsのテキストレイヤーに流し込む際に、秒とコマの情報を別々に欲しい場合もあります。

そんな時は、自作のルーチンを強化して、機能アップを図れば良いのです。

ユーザが「00+00」「00+00+00」の書式で入力した場合と、「0000」のフレーム数を入力した場合の、2つの場面に対応できるルーチンに改良します。

「どうやってみわけんの?桁数?」「IFで分岐?」‥‥とか考えがちですが、実は何も見分けなくても、前回書いたルーチンは「フレーム数の入力に対応」しています。

前回のルーチンは、

  • 6+0
  • 0+144
  • 144
  • 3+72

‥‥のどれでも、正しく処理します。これはAfter Effectsもそうで、人間が繰り上がりを計算しなくても、自動で繰り上げを計算するようプログラムされているのです。「1+18」のカット尺にボールド8コマを足した「1+26」と入れても、ちゃんと「2+2」に変換してくれます。

要は、ベタなフレーム数を計算した後、改めて「00+00」の書式を生成するルーチンに仕立てておけば、「行儀の悪い」入力でも「清書」した値を返してくれます。

また、ルーチンが返す値も単に「フレーム数」だけでなく、様々な情報を返すように強化します。AppleScriptでは「ラベル付きリスト」とか呼ばれるデータで、今回作ったルーチンは以下の値をまとめて返してくれます。

  • フレーム数
  • 尺の汎用的な書式
  • 尺のコマ数(フレーム数)を2ケタ表示にして括弧で囲んだ表示書式
  • 日(普通はいらないよね、こんな単位)
  • 時間
  • フレーム
  • 秒の表示(端数を除いた総秒数)
  • フレームの表示(2ケタ)
  • 計算に用いたFPS

ルーチンを利用する際、上記の中から、ニーズに適合するものを取り出して使います。

で、せっかくなので、単にルーチンを走らせるだけでなく、対話式のプチ「尺とフレームの変換計算」アプリケーションに仕立て上げます。

以下がAppleScriptのスクリプト文です。

--ここから

set res to text returned of (display dialog "尺またはフレーム数を入力してください" default answer "")

if length of res = 0 then
    beep
    display dialog "入力欄が空です." with icon stop buttons {"中止"} default button 1
    return
end if

set res2 to my calcFrames2(res, 24)

if res2 is false then
    beep
    display dialog "入力した文字に問題があります." with icon stop buttons {"中止"} default answer res
    return
end if

display dialog "計算結果は以下の通りです" with icon note buttons {"OK"} default answer "尺:" & durationText of res2 & "
表示書式:" & displayText of res2 & "
フレーム数:" & frames of res2


on calcFrames2(_durText, _fps)
    set delim to AppleScript's text item delimiters
    set AppleScript's text item delimiters to "+" as Unicode text
    set textitems to text items of (_durText as Unicode text)
    set AppleScript's text item delimiters to delim
   
    if length of textitems > 5 then return false
   
    set timescale to {1, _fps, _fps * 60, _fps * 60 * 60, _fps * 60 * 60 * _fps}
   
    set fc to 0
    repeat with i from 1 to length of textitems
        set textitem to item -i of textitems
        try
            set fc to fc + (textitem as integer) * (item i of timescale)
        on error
            return false
        end try
    end repeat
   
    set arr to {}
    set modfc to fc
    repeat with i from 1 to ((length of timescale) - 1)
        set arr to arr & modfc div (item -i of timescale)
        set modfc to modfc mod (item -i of timescale)
    end repeat
   
    set sec to (fc div (item 2 of timescale)) as Unicode text
    set frDisp to (characters 2 thru -1 of ((100 + modfc) as text)) as Unicode text
   
    return {frames:fc, durationText:(sec & "+" & (modfc as text)) as Unicode text, displayText:("(" & sec & "+" & frDisp & ")") as Unicode text, daysCount:item 1 of arr, hoursCount:item 2 of arr, minutesCount:item 3 of arr, secondsCount:item 4 of arr, framesCount:modfc, secondsText:sec, framesText:frDisp, fps:_fps}
end calcFrames2


--ここまで

上記スクリプトを「アプリケーション形式」で書き出すと、いつでも尺の変換計算を確認できるプチAppができます。実行してみると、



ここに何か、尺を入力します。例えば6秒ジャストの尺を色々な書式で入力してみましょう。



結果は、



‥‥とちゃんと正確に計算しております。さらに違う書式で‥‥



‥‥とか、



‥‥などでも、やはり以下の通り、正確に計算して返します。



別の尺でも、



ちゃんと変換します。



さらには、こんな表記もイケちゃいます。



1時間0分0秒0コマ。もちろん結果は、



‥‥ですネ。3600秒は1時間ですから、バッチリ、処理できてます。


仮に、尺以外の入力をした時は、



以下のようにエラー警告をおこないます。




‥‥とまあ、こんな感じで、尺の変換ルーチンに「display dialog」のGUIをくっつけて、1つの小さなアプリケーションにする事もできます。

尺の変換ルーチンは、それそのものは何らUIを持ちませんから(というか、そのように作ったので)、対話式のアプリにしたい場合は、AppleScriptの他の機能と組み合わせてアプリを作ります。After Effectsのレンダーオートメーションと連携して、コンポジションの尺や、テキストレイヤーの内容を書き換える事も可能ですネ。

次回は、尺の変換の体勢も整ったので、「尺が怪しくないか、判断してユーザに知らせる」スクリプトを作ってみます。以下のような「素敵なお知らせ」をMacがテキストエディットを使って知らせてくれます。



AppleScriptはdisplay dialogだけでなく、テキストエディットを用いて告知板にしたり、HTMLファイルを書き出してFireFoxやSafariで表示する事もできますから、ユーザへの「お知らせ方法」の手段はそれなりに豊富です。

ではまた。

尺からフレーム数への計算

アニメ制作現場では、2コマ3コマで動きのタイミングをとる事が多いので、都合、タイムシートでの尺は「傾向が偏って」きます。

例えば、「3+12」(つまり3秒半)なんていう尺は、それこそ耳にタコができるくらいお馴染みの数値です。

そんな中、QTファイルのPDF伝票で「3+11」とか「5+23」とか言う尺を見ると、「なんかやらかしたか?」と直感します。つまり、「何かの障害で、尺が足りてない」的な「危険予測」です。‥‥まあ、危険予測と言っても、既にレンダリング済みのムービーファイルの尺なので、実際は「現物を確認する前の、状況予測」なんですけども。

シートを確認してみると、「うわー、変な尺。ほんとに5+23だよ。1コマ伸ばして6+0にしときゃいいじゃん‥‥」という珍しい状況もあったりします。しかし、そんな変な尺の大体は、レンダリングの何らかの不具合による途中終了、もしくはオペレーション上のミスの場合が大半です。

なので、カットを管理するデータベースと連携しなくても、尺を見るだけで尺の不具合を発見する事ができます。もちろん、全て発見できるわけではないですが、ソフトウェア上で発生したような障害は、大体検出できます。

つまり、レンダリングしたムービーの尺を取得して、「変なコマ数」か否かをチェックするスクリプトを作れば、作業者がいちいちファイルをチェックしなくても、コンピュータが「やばそうな尺を教えて」くれる‥‥というわけです。そうやって、コンピュータを自作ツールで「育てて」いくと、次第に「作業上のパートナー」「ヘルパー」的な役割へとコンピュータが変わってきます。

今回はまず、その土台となる、尺とフレーム数の変換スクリプトを、AppleScriptにて書いてみます。やる事自体は、そんなに難しくないのは、考えればお分かりかと思います。24コマで1秒‥‥というのを、計算すれば良いのですからネ。

アニメ現場の場合、尺は通常、1秒24コマ換算で、「秒+コマ」の書式で書きます。3秒なら「3+0」、5.5秒なら「5+12」です。

尺をフレーム数に換算するのは、例えば「5+12」の場合、

5+12

‥‥を「+」で文字列分解して、

5 12

‥‥の要素に分けます。そして、

(5x24) + 12 = 132

‥‥という計算をしてやれば良い訳です。

ちなみに、After Effectsではコンポジション設定のデュレーションの欄に、「5+12」と入れると、「5秒12フレーム(コマ)」としてちゃんと認識します。さらには、「1+30+0」と入力すると、「1分30秒0フレーム」と認識します。どこまでプラス(+)の連結を受け入れるのか、怖くてやってませんが、AppleScriptでも似た構造で処理してみます。

ちょっと図にのって、「日+時+分+秒+フレーム」という5段階まで受け入れるように作ってみました。‥‥まあ、「日」単位の需要があるとは思えませんが。

my calcFrames("5+12", 24)

on calcFrames(_durText, _fps)
    set delim to AppleScript's text item delimiters
    set AppleScript's text item delimiters to "+" as Unicode text
    set textitems to text items of (_durText as Unicode text)
    set AppleScript's text item delimiters to delim
   
    if length of textitems > 5 then return false
   
    set timescale to {1, _fps, _fps * 60, _fps * 60 * 60, _fps * 60 * 60 * _fps
}
    set fc to 0
    repeat with i from 1 to length of textitems
        set textitem to item -i of textitems
        set fc to fc + (textitem as integer) * (item i of timescale)
    end repeat
   
    return fc
end calcFrames



「on calcFrames...」以下が尺をフレーム数に変換する「自作ルーチン」です。1行目の「my ...」でルーチンを呼び出して処理させます。

1行名の「my...」のかっこ内の「"5+12"」を、「"7+0+0+0+0"」(7日0時間0分0秒0フレーム)に書き換えると、7日=1週間のフレーム数が計算できます。

ちなみに7日間のフレーム数は、1451万5200フレームみたいです。

きりがないので、「1+0+0+0+0+0」(=1年)などの6つ以上の連結の場合は、「false」(偽の値〜「もうダメよ」的な)を返すようにしてあります。

こんな感じで、「処理ルーチン」を自作して、そのルーチンに値を投げ込むと、処理された値が戻ってきます。このやり方は、スクリプトが複雑化する際に、必須となります。

ファイルの分別(後)

AppleScriptでファイルの分別をする後半です。ポイントは、

  • 大量処理の場面ではFinderを使わず、高速化する
  • カット名らしき文字列を含むファイルだけを対象とする
  • 特定のファイル形式(今回はDPX)だけを対象とする

‥‥です。つまり、PSDやQT、JPEGは対象から自動的に外し、さらにはDPXファイルと言えどもカット名を含まないものも自動的に対象外とします。

そこそこ長いスクリプト文なので、まずは下記に記します。

(*

まず、手始めに‥‥

本番のファイルを使うのはマズいし、テスト用にAfter Effectsで連番ファイルをレンダリングするのもバカらしいので、「ニセの画像ファイルの連番」を作ってしまいます.

*)

set folderName to do shell script "date +%y%m%d-%H%M%S" --日付&時間の文字列を生成
tell application "Finder" --Finderに命令を開始
    activate --Finderを最前面にする
    set theFolder to make new folder at desktop with properties {name:folderName} --先ほど生成した文字列を名前にしてフォルダ(=テストの作業場所)をデスクトップに作る
    open theFolder --作ったテスト用フォルダのウィンドウを開く
end tell --Finderへの命令終了

set folderPath to theFolder as Unicode text --フォルダをパス文字列に変換する
set countOfFiles to 720 --カット毎の連番ファイル数を指定
set dummyCutNames to {"dummy_02_165_t1", "dummy_01_014_t2", "anime_12_254a_t1", "dummy_02_098_t3", "test_a_211_t3", "test_a_211_t4"} --架空のカット名を生成

repeat with dummyCut in dummyCutNames --ダミーのカットで繰り返し処理
    repeat with i from 10001 to (10000 + countOfFiles) --10001から数え始めて指定ファイル数へ繰り返し処理
        set ofa to open for access file ((folderPath & dummyCut & "_" & ((characters 2 thru -1 of (i as text))) as Unicode text) & ".dpx") with write permission --テスト用フォルダ内にカット番号+4桁連番+拡張子の名前のダミーファイルを作ってアクセス開始
        write "dummyだよん" to ofa --dummyという文字列を書き込む(テキトーな文字)
        close access ofa --ファイルへのアクセスを終了する
    end repeat --繰り返し処理終了
end repeat --繰り返し処理終了

--テストフォルダの中には、5秒前後で数千個のファイル(自動処理のテスト用の偽ファイル)が生成された、はずです.

--故意に他の拡張子のファイルも数種類混ぜてみましょう
--名前でソートした際にごちゃごちゃになるよう、わざとイジワルな名前をつけて、スクリプトの耐久性を見ましょう
repeat with dummyFile in {"A-関係ないPhotoshopファイル.psd", "B-関係ないQuickTimeファイル.mov", "s_全く関係ないJPEGファイル.jpg", "Y_消し忘れたPNGファイル.png", "0-素材のイラレファイル.ai", "testで書き出したDPX.dpx"}
    set ofa to open for access file (folderPath & dummyFile) with write permission --偽ファイル
    write "dummyだよん" to ofa --dummyという文字列を書き込む(テキトーな文字)
    close access ofa --ファイルへのアクセスを終了する
end repeat



activate --このスクリプトを最前面にして
set theResult to display dialog ((length of dummyCutNames) as text) & "カットの合計" & ((countOfFiles * (length of dummyCutNames)) as text) & "ファイルを生成しました" with icon note buttons {"ここで止めとく", "分別を処理してみる"} default button 1 giving up after 20 --処理の続行を尋ねる
tell application "Finder" to activate --Finderを最前面にする(処理の様子を見せる)
if button returned of theResult is "ここで止めとく" then return --ユーザが中止を選択した場合は処理を中止


(*


これより以下がフォルダごとの分別処理です.
回りくどいトリッキーな事をしているように見えますが、「できるだけFinderを大量のファイルに関与させない」工夫ゆえです.

*)

set cutNameSliceStart to 1 --カット名を抜き出す開始番号(アンダースコアで区切った配列のスタート)
set cutNameSliceEnd to 4 --カット名を抜き出す終了番号(アンダースコアで区切った配列のエンド)
set nameExtension to ".dpx" as Unicode text --収拾するファイルの拡張子を設定
set AppleScript's text item delimiters to "_" as Unicode text --ファイル名のリスト分解に備える

set tryCount to 0 --検索ファイルのカウント
repeat --無限の繰り返し
    set tryCount to tryCount + 1 --検索ファイルのカウントを1つ増やす
    try --エラー発生を見越して(故意にエラーを発生させる)
        tell application "Finder" --Finderに命令
            set theFile to file tryCount of theFolder --分別のきっかけとなるファイルを指定
            set theFileName to (name of theFile) as Unicode text --ファイルの名前を取得
        end tell --Finderへの命令終了
    on error --ファイルを検索し終えた場合にエラーが出る
        activate --このスクリプトを最前面に呼び出して
        display dialog "処理が終了したようです.
       
ちゃんと分別されたか、Finderのウィンドウで確認してみてください.

分別対象以外のファイルはそのまま残っています." with icon note buttons {"OK"} default button 1 giving up after 15 --処理終了を報告する
        exit repeat --無限ループから脱出
    end try --故意エラーへの対応終了
   
    if theFileName ends with nameExtension then --もしファイルが対象ファイル形式だったら
        set nameArray to text items of theFileName --ファイル名をリスト(配列)分解
        set fileNameCheckIsOK to length of nameArray > cutNameSliceEnd --ファイル名が規定を満たすかをチェック
        if fileNameCheckIsOK then --もしファイル名が規定を満たす場合
            set tryCount to tryCount - 1 --検索ファイルのカウントを1つ戻す(カウントの空滑りを防止)
            set cutName to (items cutNameSliceStart thru cutNameSliceEnd of nameArray) as Unicode text --カット名をファイル名から抽出する
            do shell script "mkdir " & quoted form of POSIX path of (folderPath & cutName) --フォルダをシェルで作る
            do shell script "mv " & (quoted form of POSIX path of (folderPath & cutName)) & "_*" & nameExtension & " " & quoted form of POSIX path of (folderPath & cutName) --対象ファイルをカット名フォルダに移動する
        end if --ファイル名チェックの「もし」の範囲、ここまで
    end if --対象ファイル形式の「もし」の範囲、ここまで
end repeat --無限ループの範囲、ここまで

set AppleScript's text item delimiters to "" --リスト分解の設定を初期値に戻す

tell application "Finder" to activate --Finderを最前面にする

return tryCount --検索ファイルの最終カウントを結果として戻す


コメントを入れたおかげで、余計、長く感じられますが、まだシンプルなほうだとは思います。やっている事が、単にファイルの分別ですからネ。テスト用の偽物ファイルを作るところからやっているので、長くなっているのですネ。

動作中のスクリーンショットは、こんな感じ。

スクリプトを実行すると、デスクトップに日付のフォルダが自動生成され、その中に数秒後、テスト用のダミーファイルが大量生成されます。

5040個の連番ファイルと、故意に混ぜた関係のないファイル6個。変更日でソート表示されてるので、並びはバラバラですが、ウィンドウ下部の項目数に注目してください。





…実際に作ったのは、上記の通り、5040+6で5046ファイル。

「分別を処理してみる」ボタンをクリックすると、数秒後‥‥

‥‥のような感じで、思惑通り、カット名を持つ連番ファイルだけが、分別されました。イジワルな名前の混在にもメゲず、ちゃんとカット名連番だけを見分けて、新規フォルダを作って格納しています。

種類でソートすると、こんな感じ。

めでたく、終了。5046項目のごちゃまぜファイルが、数秒で、スッキリ、13項目に整理されました。


たとえ、以前にレンダリングしたQTファイルや、とりあえず置いといたJPEGファイルがあっても、「カット名を含む、DPX」以外は処理対象から外すので大丈夫なのです。

また、作品や話数がごっちゃになっていても、「カット名の命名規則に準じて」ファイルを選別するので、問題無いのです。

スクリプトの文中に目を通すと、AppleScript独特の表現もちらほら見えます。「AppleScript's text item delimiters」なんてのは、その最たるもので、私はこれが面倒でイヤなんですが、要は「テキストの要素を分解する文字」の事です。これを操作すると、文字列を任意の文字で分解できるようになります。

ファイルを分別するくだりは、目の前にあるものを処理して、もし対象外のものだったら、一歩進む‥‥という、何とも可愛い動作にしてあります。一歩進む‥‥とは、「自分のいる位置のカウントを1つ足す」という事ですが、AppleScriptには「++」なんてシャレたものはないので、set その変数 to その変数+1 みたいにして、地道に書きます。

Finderは言わば窓口。そこに大量の物品を持ち込んでもパニックになるだけです。窓口で簡単な手続きを済ませたら、後は頼りになるバックヤードでドカンと大量処理するのです。

しかし、AppleScriptに馴れていない人が、上記スクリプト文を読んでも、理解できないかも知れません。コメントだけ読んで、流れを汲んでもらえればと思います。文中の細かい説明はまたいずれ。

今回はダミーファイルまでも作るデモ的なスクリプトですが、文中後半の「ファイル分別ルーチン」を抜き出してちょっと手直しすれば、汎用性があって何度でも使い回しのできる、連番分別アプリケーションに育てる事ができます。

次回は、似たようなスクリプトを使って、「作業者にツッコミをいれる」スクリプトを作ってみます。データベースを使わなくても、スクリプト自身が判断して、「ほんとに、その尺で合ってる?」とユーザに確認してくるのです。

ではまた。

ファイルの分別(中)

ドロップレットAfter Effectsで出力した連番やQTを整理するスクリプト。実は、運用やワークフローがどれだけ考え抜かれているかを示す「試金石」のようなものです。

スクリプトでうまく処理できない運用ルールやワークフローは、未発達で穴が多い、もしくは、理路整然としてなくて複雑である証拠です。複雑怪奇な運用ルールは、コンピュータだけでなく、人間も往々にしてミスを連発します。「IF分岐が多過ぎる」と言いますか。

誰もが短時間でルールを理解できる運用方針は、その運用の過程で働く人間に優しいのはもちろんの事、コンピュータでも処理しやすいのです。

複雑で大風呂敷を広げたフローは、素人さんは「すげー」とか関心しがちですが、多様な現場に接してきたプロの目からすると、「メンテが大変そう。もっとシンプルにできなかったんだろうか‥‥」と気の毒になるフローです。複雑なフローはそれだけで、時間やお金、体力とメンタルに、負荷を及ぼすからです。
*納得ずくで背負い込む覚悟の作品もあるでしょう。その場合は金と人と時間に対して覚悟する‥‥という事ですネ。

シンプルで澱みがなく、INOUTが明確であるのが理想ですが、「一生懸命取り組むほどに、フローや運用を複雑にしてしまう」事も少なくありません。運用上の笑い話で「チェックが甘いからこのようなミスが出るのだ。ならば、ちゃんとチェックしたか、さらにチェックするようにしよう。」なんてのがあります。「なぜミスが出たか」を解消しようとはせず、チェックだけを何重にも上乗せしていく‥‥のは、誰もが「馬鹿っぽいやり方」だと感じるはずなんですが、結構、ありますよネ、そういうの。

さて‥‥。「地獄絵図のようなごちゃ混ぜのフォルダ」内から、連番ファイルを抜き出し、カットごとのフォルダにまとめるスクリプトですが、まずはファイル名から「カット名」(今回の場合「クリップ名」と呼んでも)を抜き出す方法から。

anime_01_123_t1_0001.dpx

上記のファイル名は、「anime」という作品略号の、「01」話、カット「123」、テイク「1」の、連番1フレーム目のDPXファイルです。

まず、ドットで分解すると、

anime_01_123_t1_0001 dpx

‥‥の2要素になり、さらに分解した1番目の要素を、アンダーバーで分解すると、

anime 01 123 t1

‥‥のように、カットの情報をカテゴリで分解できます。

今回の分別処理は、「作品、話数、カット番号、テイク」をひとかたまりとして扱い、分別しようと思います。つまり、

anime_01_123_t1_0001.dpx から anime_01_123_t1 を抽出したい

‥‥わけです。

何が入っているか特定できない状況において、ファイル名から「作品_話数_カット番号_テイク」を抽出し、その文字列をキッカケにしてファイルを収集する‥‥わけですネ。


さらに次。

何千項目入っているか数がわからないフォルダを相手に、Finderでファイル数を数えようとして「count of files」なんてやったら、またレインボーカーソルかも知れません。ここはひとつ、「ファイルの総数なんて数えないで、先頭のファイルからどんどん喰っていく」やりかたで処理します。「わんこそば」のように、「目の前にある項目を処理していく」やりかたです。

何度も書いてきた通り、大量の項目を処理しようとすると、Finderは破綻するわけですから、Finderには項目を1つだけ渡して順次処理するようにすれば、破綻せずに済みます。あくまで「使いよう」を考えます。

処理ルーチン上で、ファイルをひとつずつ処理し、条件に合った場合は、ファイルを収集して新規フォルダに移動します。これを、ファイルに全部目を通しきるまで、繰り返して処理します。

処理に適合する条件は、

  1. DPXファイルであること
  2. カット名を含んでいると予測できるもの

‥‥の2種です。もっと条件を増やしても良いでしょうが、カット名(らしき)を含んでいて、DPXファイルであれば、かなり特定できますから、今回はシンプルなこの2つの条件だけで処理します。

  • DPXファイル→ファイル名が「.dpx」で終わる
  • カット名を含んでいる→アンダーバーで文字列分解して要素数が5以上のもの

‥‥まあ、条件が甘いような気もしますが、運用とワークフローの前提が「そこそこ、要素を絞り込んでくれてる」ので、これでも充分上手くいきます。



‥‥と思ったら、またこんなに文がかさんでおる。なので、締めは次回に。



ファイルの分別(前)

AppleScriptは映像制作で役立てようとすると、結構、使い方に「コツ」が要ります。「コツ」なんていう言い方をするのは、「基本に忠実で、理屈にかなっていても、うまく動かない時がある」からです。

例えば、5,000項目を取り扱うような場合は、市販参考書に書いてあるやりかたではダメです。市販参考書は、まさか5,000項目なんて処理するとは想定していないのですから。

例えば。

「anime_01_065_t1_」で名前が始まるファイルを抽出せよ‥‥などの時は、普通は「フィルタ参照形式」という方法で抜き出すのが基本ですが、相手が5,000項目ともなると、レインボーカーソルが回ったまま、Finderが応答しなくります。ビジー状態による、事実上のフリーズですネ。

move files of folder "MacHD:testfolder:" whose name starts with "anime_01_065_t1_" to folder "MacHD:testfolder2:"

そんな時は、無理せず、do shell script。Finderは、数千項目などの処理には「全く向かない」と考えて、他の手段で抜き出します。

do shell script "mv " & (POSIX path of "MacHD:testfolder:anime_01_065_t1_*")& " " & (POSIX path of "MacHD:testfolder2:")

なんのヒネリもないmvコマンドですが、AppleScriptと組み合わす事によって、様々なアプリケーションと連携が可能です。

でもまあ、上記の例だと、AppleScriptのうまみはほとんどない‥‥ですネ。ターミナルでやりゃ良いんだもん。

AppleScriptを使う以上、汎用性の高い、「カットごとの分別はおまかせ」的なツールに仕立て上げたいですよネ。

で‥‥、今回(と次回)のテーマは、「ファイルの分別」です。

AppleScriptは、「大量のファイルを捌くのは苦手」‥‥とされてきました。Finderの挙動が、誤解を招いてきたのかも知れません。

しかし、使い方次第で、いくらでも高速化できる事を、実践してみたいと思います。UNIXが見方ダヨ。

「レンダリングフォルダの中に、何カットものDPX連番ファイルを出力した」「カットごとにフォルダを分別するのが面倒」「After Effectsでフォルダを毎回指定するのも面倒」「さらには、関係ないPSDファイルやJPEG、QTファイルもあり、ごちゃごちゃになっている」「しかも、数は5,000ファイルを超える」

‥‥まあ、こんな事になる前に、After EffectsでESTKスクリプトを実行して、「連番ファイルの親フォルダを作る」のを自動化すれば良いんでしょうが、それはまた別の機会に。

とにかく、地獄絵図のようなフォルダの中から、「アンダーバーで区切られたカット名を持つファイルを、それぞれカットごとにフォルダを新作して分別する」ミッションを、AppleScriptにてクリアしたいと思います。


まずは、事前の確認。。。

カット名の規則は‥‥

作品名_話数またはシーン_カット番号_tテイク番号_連番.ファイル拡張子

という運用がなされているものとします。別の命名方法でも良いんですが、今回はこの命名規則を用います。

ちなみに‥‥

「いや‥‥。カット名も実は、作業者毎、個人個人バラバラで‥‥」

‥‥とか言う場合は、「運用のところ」から見つめ直しましょう。決まった法則でファイル名を運用出来てないのは、すなわち、「私(私たち)は価値ある時間を、混乱の収拾のために、無駄に費やしたいのです」と宣言しているようなもんです。最低でも「各作業セクション内では統一した規則で運用」すべきで、「自動処理以前に、まず運用の基本を形成して楽になろう」‥‥ですネ。

ワークフローを軽視せず、命名規則もキチンと規定してあれば、AppleScriptは守護天使のように、作業者・クリエーターに力を授けてくれます。

では後半へ続く。


calendar

S M T W T F S
   1234
567891011
12131415161718
19202122232425
262728293031 
<< March 2017 >>

selected entries

categories

archives

links

profile

search this site.

others

mobile

qrcode

powered

無料ブログ作成サービス JUGEM