#はじめに
ADX2スクリプトで原音再生の改良版の紹介。
環境:CRI AtomCraft 3.45.00
#スクリプトの流れ
UI系は外部プロセスにしないとCraftごと落ちてしまうことがわかっていて、
バッチみたいな処理にしか利用できていないのが現状なのだけど、
- 情報収集(選択キューのマテリアルを探し元ファイルパスを得る)
- 解析 (今回はとくになし)
- 実行 (音を再生する)
という流れの、
情報収集だけCraft上で動作させて、
解析、実行を別プロセスにしておくと、
Craftを解放できるはず
##別プロセスのメリット
- 中断ができる(プロセスを止めることができる)
- 非同期実行にできる(重い解析とかでCraftを待たせなくすることができる)
- Craft上でのスクリプトの実行の制限から解放される
- UIが表示できる(解析結果表示など)
- スクリプト分割時の更新など(Craftは一度importしてしまうとCraft再起動するまで外部ファイルの再読み込みをしないため)
##別プロセスのデメリット
- ファイルが増える
- デバッグや、結果の収集、インタラクティブなやりとり(プロセス間通信)に少し工夫が必要になる。
(Craftはサーバー機能でもスクリプト動かせるので駆使すればできなくはないが)
改善点
###長い音の再生をキャンセルできない問題
前回の再生の場合、同じプロセスで再生をしてしまうため、
曲のような長い音を再生した場合、再生が終わるまで待たないといけない状態でした。
そこで、再生処理を別プロセスに投げてしまうことで、キャンセルできるようにします。
キューを選択し、PlayWav.pyを実行すると
マテリアルのフルパスを得ることができ、
subprocessを利用して
Z_ExtAudioPlay.pyを実行します。
引数の波形を再生します。
また、再生しているウィンドウを閉じることで、中断することができます。
プロセスを起動するスクリプト
PlayWav.py
# --Description:[tatmos][Preview]選択したオブジェクトの原音を再生
import subprocess
from time import sleep
import cri.atomcraft.project as acproject
import cri.atomcraft.debug as acdebug
#--------
#選択中のマテリアルまたはウェーブフォームリージョンまたはキューを得る
selectedMaterials = acproject.get_selected_objects("Material")["data"]
selectedWaveformRegions = acproject.get_selected_objects("WaveformRegion")["data"]
selectedCues = acproject.get_selected_objects("Cue")["data"]
selectedMaterial = None
if len(selectedMaterials) > 0:
selectedMaterial = selectedMaterials[0]
if len(selectedCues) > 0:
selectedWaveformRegions = acproject.find_objects(selectedCues[0],"WaveformRegion")["data"]
if len(selectedWaveformRegions) > 0:
selectedMaterial = acproject.get_value(selectedWaveformRegions[0], "LinkMaterial")["data"]
if not selectedMaterial:
acdebug.warning("再生するマテリアルまたはウェーブフォームリージョンまたはキューを選択してください。")
sys.exit()
print(acproject.get_value(selectedMaterial, "Name")["data"])
input_path = acproject.get_value(selectedMaterial, "SrcFileAbsolutePath")["data"]
if not input_path:
acdebug.warning("マテリアルのパスがみつかりません。")
sys.exit()
print("Path:" + str(input_path))
#別プロセスで再生
command = ["python","C:/MyDearest/github/ADX2Robot/local/Z_ExtAudioPlay.py",input_path]
proc = subprocess.Popen(command)
proc.communicate()
再生をするスクリプト
Z_ExtAudioPlay.py
import pyaudio
import wave
import time
import sys
args = sys.argv
input_path = args[1]
p = pyaudio.PyAudio()
#--------
#AUDIOのDEVICEを列挙
#hostAPICount = p.get_host_api_count()
#for cnt in range(hostAPICount):
# print(a.get_host_api_info_by_index(cnt))
#音を鳴らすDEVICEを指定
DEVICE_INDEX = 0
#--------
#ファイルを開く
wf = wave.open(input_path, "rb")
def callback(in_data, frame_count, time_info, status):
data = wf.readframes(frame_count)
return (data, pyaudio.paContinue)
#ストリームの作成
stream = p.open(format=p.get_format_from_width(wf.getsampwidth()),
channels=wf.getnchannels(),
rate=wf.getframerate(),
input_device_index = DEVICE_INDEX,
output=True,
stream_callback=callback)
#再生
stream.start_stream()
print("再生中 ... " + input_path)
#再生終わりまで待つ
while stream.is_active():
time.sleep(0.1)
print("done.")
stream.stop_stream()
stream.close()
p.terminate()
wf.close()