見出し画像

DavinciResolve APIのText+関係のメモ

ものすごい久しぶりのnote更新ですがソードオブガルガンチュア関係ないです!


今年の1月に初めてVOICEROID実況動画を投稿したのですが、どうにも台詞の尺が動画に合わなくて大変苦労しました。

できれば効率よく作成したいと思い立ち、現在は勢いのままにDaviniciResolveとソフトウェアトークの連携ツールを作成するためにスクリプトを組んでいるのですが結構苦戦しています。

どうやらDaviniciResolve APIではタイムラインへオブジェクトを配置することはできるものの削除ができません。
加えて、配置するビデオトラックやオーディオトラックを指定できないことがわかりました。
スクリプトで配置できるのは赤い枠に囲まれてるトラック番号の、現在のタイムコードからのみ。(画像はビデオトラック1、00:00:19から)

指定のファイルを1トラックに一括配置するくらいなら問題ないのですが、テキスト配置後に表示内容や表示時間を変えるのは大変難しいです。
せめて配置先のトラック設定ぐらいはできなかったのか……。

ですが、スクリプトでもText+を活用すれば指定時間ごとに表示内容を変えることができるらしいので、頑張って調べました。

私はプログラミングがExcel VBAを独学でちょっと組むぐらいでLuaに触れるのは初めて。かつDaviniciResolveもあまり習熟していません。
正直に言えばこういう記事を書くにはあまりにも力量不足なのですが、DaviniciResolve API周りの日本語情報がほとんどありませんので、備忘録を兼ねて簡単に記事を残しておきます。

以下のコードは色々とコピペしながら試しながら書いたものなので、文法周りはご容赦ください。

(2022/11/9追記)
この記事は知識が足りてなかったりする(特にGetToolListでノードを取得する際に問題がある)ので、もし参考にする場合は以下の記事のコードをオススメします。

https://note.com/hitsugi_yukana/n/n8272caf8e164



TimelineへText+を挿入・編集するLuaスクリプトの例

resolve = Resolve()		--Rosolveオブジェクト取得
projectManager = resolve:GetProjectManager()	--プロジェクトマネージャー取得
project = projectManager:GetCurrentProject()	--現在読み込まれているDaVinci Resolveプロジェクト取得 
timeline = project:GetCurrentTimeline()    --現在のタイムライン取得
 
timeline:SetCurrentTimecode("00:00:10:00")	-- Text+の挿入前に指定タイムコード(hh:mm:ss:00)へ移動:成功するとtrue

newtext = timeline:InsertFusionTitleIntoTimeline("Text+") 	--Text+挿入(返却値は挿入したText+)
toolList = newtext:GetFusionCompByIndex(1):GetToolList()        --Fusionに設定されたツール一覧取得(1番目にText+、2番目にMediaOut)

-- キーフレームごとに表示内容を変えない場合
toolList[1].StyledText = "キーフレーム指定なしの文章挿入テスト"    -- 表示するテキスト設定

-- 設定したテキスト内容を表示したい場合
print(toolList[1].StyledText[0])          --StyledTextのインデックスにキーフレームを指定する
                                          --挿入時にキーフレームを指定しない場合、キーフレーム0から開始という扱いになるらしい


-- キーフレームごとに表示内容を変える場合
comp = newtext:GetFusionCompByIndex(1)
comp.CurrentTime = 0              -- アニメーションキーフレームを0にセット(今回必要なのかはわからない)
spline = comp.BezierSpline()
toolList[1].StyledText = spline   -- ベジェスプラインを設定

toolList[1].StyledText[0] = "Frame0"       --キーフレーム0から表示するテキスト
toolList[1].StyledText[10] = "Frame 10"    --キーフレーム10から表示するテキスト
toolList[1].StyledText[50] = "Frame 50"    --キーフレーム50から表示するテキスト
toolList[1].StyledText[100] = "Frame 100"  --キーフレーム100から表示するテキスト

-- 設定したテキスト内容を表示したい場合
print(toolList[1].StyledText[100])          --StyledTextのインデックスにキーフレームを指定する

dump(toolList[1].StyledText:GetKeyFrames())  -- 設定したキーフレーム一覧表示
--[[
出力される内容
table: 0x00482360
	1 = 0
	2 = 10
	3 = 50
	4 = 100
--]]

-- 指定範囲のキーフレームを削除
del_spline = toolList[1].StyledText:GetConnectedOutput():GetTool()
del_spline:DeleteKeyFrames(0, 50)        -- キーフレーム050の内容を削除
dump(toolList[1].StyledText:GetKeyFrames())  -- 設定したキーフレーム一覧表示
--[[
出力される内容
table: 0x00482360
	1 = 100
--]]

実用化するにはプロジェクトの動画フレーム設定などを取得して合わせる必要などがあるので全然足りませんが、まあ要点は抑えているかなと思います。


割とひっかかりそうなポイント

  1. Text+の新規挿入は「timeline:InsertFusionTitleIntoTimeline("Text+")」

  2. Text+のStyledTextのキーフレーム削除を行う場合は「.StyledText:GetConnectedOutput():GetTool()」でBezierSplineを取得する必要がある

まず引っかかりポイント1、Text+の挿入ですが、Text+は「timeline:InsertFusionTitleIntoTimeline()」で挿入します。「timeline:InsertTitleIntoTimeline()」ではありません。

テキストやスクロールというTitleの類を挿入する場合はtimeline:InsertTitleIntoTimeline("Text")という感じで作成するのですが、インスペクタの最上段に表示される通り、Text+はTitleではなくFusion Titleの仲間なので同メソッドでは作成できません。

Text+は最初からFusionコンポジションを持ってるので当然といえば当然なのですが、私のようにFusionを使わない人は多分引っかかるんじゃないでしょうか。

ツールボックスではText+は「タイトル」にまとめられているが……
インスペクタを確認すると「Fusion Title」に属することがわかる。罠でしょこんなん。


次に引っかかりポイント2、Text+のキーフレーム内容の削除です。
上記のスクリプト例ではStyledTextプロパティにcomp.BezierSpline()を設定しています。
そして StyledText:GetKeyFrames() で設定したキーフレーム一覧も取得できます。
じゃあStyledText:DeleteKeyFrames()でキーフレームも削除できると思うでしょう?
できないんですよね。

下記のように、GetID()メソッドでクラスを確認して見ると、StyledTextの方がInputクラスであることがわかります。
InputクラスにはDeleteKeyFrames()メソッドはないため、StyledText:DeleteKeyFrames()を実行しようとするとエラーになります。

print(spline:GetID())                  -- 出力結果:BezierSpline
print(toolList[1].StyledText:GetID())  -- 出力結果:Input

こちらのフォーラムのやりとりを参考にしたところ、代入処理を別の処理でオーバーロード(上書き)してるんじゃないか? ってことらしいです。

代入元であるsplineからなら削除することはできます。spline:DeleteKeyFrames()ならエラーは出ません。
とはいえ変数に格納した一時的な値なので、スクリプトを実行中ならともかく、スクリプトの実行終了後以降もデータを保持し続けることはできません。

既に配置したText+を編集するのであれば、該当するBezierSplineクラスを抽出する必要があります。

配置したText+から該当データを取得してキーフレーム内容を削除する方法ですが、まあスクリプト例に書いてある通り、StyledText:GetConnectedOutput():GetTool()で取得できます。

代入元のsplineから削除するのでなく、del_spline に一度抽出してから削除しているのは流れをわかりやすくするためです。



その他参考情報

  • BezierSplineクラスについてはこちらのドキュメントの52ページ以降参照

  • その他の主要なクラスについてはDavinciResolveScriptのドキュメントページ(Chromeの翻訳でも十分役立ちます)

  • DaviniciResolve API の各クラスについてはResolve():GetHelp("クラス名")で取得できます。引数に何も渡さなければGetHelpでヘルプを見れるクラスの一覧を取得できます。

ヘルプと言っても引数や返却値は書いてないのがほとんどなので、そのままだと使えないメソッドも結構多いです。検索キーワードを探すのには便利。ドキュメントやGoogle検索と組み合わせて調べるのが良いのでしょうね。

dump(resolve:GetHelp('Timeline'))    -- Timelineクラスのヘルプ表示
--[[
出力結果

Timeline Members:
  Timeline:AddMarker()
  Timeline:ApplyGradeFromDRX()
  Timeline:CreateCompoundClip()
  Timeline:CreateFusionClip()
  Timeline:DeleteMarkerAtFrame()
  Timeline:DeleteMarkerByCustomData()
  Timeline:DeleteMarkersByColor()
  Timeline:DuplicateTimeline()
  Timeline:Export()
  Timeline:GetCurrentClipThumbnailImage()
  Timeline:GetCurrentTimecode()
  Timeline:GetCurrentVideoItem()
  Timeline:GetEndFrame()
  Timeline:GetItemListInTrack()
  Timeline:GetItemsInTrack()
  Timeline:GetMarkerByCustomData()
  Timeline:GetMarkerCustomData()
  Timeline:GetMarkers()
  Timeline:GetName()
  Timeline:GetSetting()
  Timeline:GetStartFrame()
  Timeline:GetTrackCount()
  Timeline:GetTrackName()
  Timeline:GrabAllStills()
  Timeline:GrabStill()
  Timeline:ImportIntoTimeline()
  Timeline:InsertFusionGeneratorIntoTimeline()
  Timeline:InsertFusionTitleIntoTimeline()
  Timeline:InsertGeneratorIntoTimeline()
  Timeline:InsertOFXGeneratorIntoTimeline()
  Timeline:InsertTitleIntoTimeline()
  Timeline:SetCurrentTimecode()
  Timeline:SetName()
  Timeline:SetSetting()
  Timeline:SetTrackName()
  Timeline:UpdateMarkerCustomData()
  ResolveScriptable:Print()
  .ClassName [R]
  :GetApp()
  :GetAttrs()
  :GetHelp()
  :GetHelpRaw()
  :SetAttrs()

--]]



内容としては以上となります。

DavinciResolveスクリプトの日本語情報もっと増えて欲しいと願いつつ、それよりもまずAPIの使いにくさをどうにかしてほしいなと思うのでした。

サポートしていただけるとその分の価値を提供できてるんだなって励みになります。