#ADX2 ロボットで音声の個数と尺の合計を得る

#はじめに
音声を収録した時に、各ボイスがどれくらいあるのか知りたい時があったので [ADX2ロボット機能](https://game.criware.jp/manual/adx2_tool/latest/criatom_tools_atomcraft_api.html) で作ってみました。

#スクリプトの内容

1. 検索対象のキューシートを得る
2. キューを取得
3. キューのコメントに特定文字が含まれていたら個数と尺を足す


という流れ。

#キューのコメント
キューのコメントには、検索キーワードが埋め込まれているので、その文字列が含まれていたらカウント対象としています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/96808/c63f8dee-565e-3e49-3c93-697e5dd46ed9.png)

余談ですが、コメントにこういう文字入れるのも結構手間なので自動化したいところ
（こういう波形に関する演出メタ情報のようなものは別途エクセルやGSSで管理されている）

#キューの長さ
波形の長さはキューに登録されている最初のウェーブフォームリージョンだけ計測しています。
（複数入っている場合などの考慮はしていない）


## まじめに長さをとろうとすると結構大変
以下のようなことが考えられる
- ピッチが異なると長さも変化する
- 再生速度が異なると長さも変化する
- ループ波形とかあると長さをどこにするか基準が必要（データ長なのか、実再生時間がほしいのか）
- アクションや、キューリンクなどある場合は、その先の内容をたどらないといけない
- ブロックとかあると、何を長さとして得たいのか曖昧になる
- セレクタや、ランダムトラック再生とか、再生確立など、再生ごとに長さが変わってしまう要因がある場合にどうするか？

などは、おそらく用途によって必要な処理が変わると思います。

今回はボイスのキュー対象なので、いろいろ端折っています。


#言語の対応
言語対応している波形は、参照してるウェーブフォームリージョンを言語に応じて探索しなおさないといけない。

フォルダ構成はこんな感じなので、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/96808/4ae7731e-44a5-d725-cd1a-074d06e1f8f0.png)

パスに含まれるフォルダ名を置換することで対応しています。

スクリプトでは、
language = "ja"
というところを
language = "en"
にすると英語の波形の長さを取得します。



# スクリプト


``` CountWaveLength.py

# --Description:[tatmos]キューのコメントに特定文字があるものをカウントし、総尺を出力する
import sys
import cri.atomcraft.project
import cri.atomcraft.project as acproject
import cri.atomcraft.debug as acdebug
import cri.atomcraft.preview as acpreview

# 選択しているキューシートを得る
selected_CueSheets = acproject.get_selected_objects("CueSheet")["data"]
if not selected_CueSheets :
    acdebug.warning("解析するキューシートを選択してください.")
    sys.exit()

cues = list()
#キューを取得
for cusheet in selected_CueSheets:
    acdebug.log("cusheet Path:\"{0}\"".format(acproject.get_object_path(cusheet)["data"] ))
    #キューを集める 
    cues = acproject.find_objects(cusheet, "Cue")["data"]    

language = "ja"
languageFolderJa = "/ja/"
languageFolderEn = "/en/"

#キューのコメントに特定文字が含まれていたら個数と尺を足す
def CheckLength(targetName):
    #acdebug.log("Name:\"{0}\"".format(targetName ))
    count = 0
    length = 0
    for cue in cues:
        if targetName in acproject.get_value(cue, "Comment")["data"]:
            count+=1
            #長さを得る
            waveformRegions = acproject.find_objects(cue, "WaveformRegion")["data"]  
            
            #リンクされているマテリアルを取得
            tmplinkMaterial = acproject.get_value(waveformRegions[0], "LinkMaterial")["data"]
            tmplinkMaterialPath = acproject.get_object_path(tmplinkMaterial)["data"] 
            #acdebug.log("Target Path:\"{0}\"".format(tmplinkMaterialPath ))
            linkMaterialPath = tmplinkMaterialPath

            #言語フォルダーのマテリアルパスに変更
            if language == "ja":
                linkMaterialPath = tmplinkMaterialPath.replace(languageFolderEn,languageFolderJa)
            else:
                linkMaterialPath = tmplinkMaterialPath.replace(languageFolderJa,languageFolderEn)

            #言語フォルダーのマテリアルに変更
            resultMaterial = cri.atomcraft.project.get_object_from_path(linkMaterialPath)
            #acdebug.log("resultMaterial :\"{0}\"".format(resultMaterial["succeed"] ))
            #acdebug.log("resultMaterial :\"{0}\"".format(resultMaterial["data"] ))
            if resultMaterial["data"]:
                #acdebug.log("resultMaterial :\"{0}\"".format(linkMaterialPath ))
                linkMaterial = resultMaterial["data"]
            else:
                #acdebug.warning("Not Found Target Path:\"{0}\"".format(linkMaterialPath ))
                linkMaterial = cri.atomcraft.project.get_object_from_path(tmplinkMaterialPath)["data"] #みつからない時


            #波形の長さを計算
            samplingRate = acproject.get_value(linkMaterial, "SamplingRate")["data"]
            sampleFrames = acproject.get_value(linkMaterial, "SampleFrames")["data"]
            length+= float(sampleFrames)/float(samplingRate)

    acdebug.log("Name:\"{0}\" Count:\"{1}\" Length:\"{2:.2f}\" {3}".format(targetName,count,length,language))
            
CheckLength("クロエ")
CheckLength("ノア")
CheckLength("ジュリィ")
CheckLength("アオバ")
CheckLength("コーコ")
CheckLength("ヤマト")
CheckLength("デイター")
CheckLength("アニマ")

```

実行するとこんな感じでログに出力されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/96808/fd38b5d0-c487-d5a0-8971-fe66dff69445.png)


# おわりに
どちらかというと分析ツールに近いものなのですが、
こういうものを用意しておくと、日本語と英語でどれくらい長さの傾向が違うとか、話者ごとの比較とかできて便利そうです。
違うアプローチで何か調べたいとかいった時にも応用できそうです。

もし、総尺が知りたいとかあったとき、手動だとめちゃめちゃ大変なので、ADX2ロボット機能はとてもありがたい。