はなちるのマイノート

Unityをメインとした技術ブログ。自分らしくまったりやっていきたいと思いますー!

【Unity】エディタ上でスクリプトからAudioClipを再生する(Unity 2020.2からPlayClip -> PlayPreviewClipになったので注意)

はじめに

今回はエディタ上でスクリプトからAudioClipを再生する方法を書きたいと思います。

具体的な利用場面は、EditorWindow内でボタンを押したら音声を出力したいといった場合とかですかね。

概要

エディタ上で音声を再生するAPIUnityは公式で用意してくれていません。

ただUnityEditor.AudioUtil.dllに含まれるAudioUtilクラスをリフレクションを用いて利用することで音声を流す事ができます。
github.com

内部実装はc++で記述されているので見る事はできませんが、そのC#ラッパーはUnityCsReferenceより見る事ができます。

namespace UnityEditor
{
    [NativeHeader("Editor/Mono/Audio/Bindings/AudioUtil.bindings.h")]
    [StaticAccessor("AudioUtilScriptBindings", StaticAccessorType.DoubleColon)]
    internal class AudioUtil
    {
        [StaticAccessor("GetAudioManager()", StaticAccessorType.Dot)]
        extern public static bool resetAllAudioClipPlayCountsOnPlay { get; set; }

        [StaticAccessor("GetAudioManager()", StaticAccessorType.Dot)]
        extern public static void PlayPreviewClip([NotNull("NullExceptionObject")] AudioClip clip, int startSample = 0, bool loop = false);

        [StaticAccessor("GetAudioManager()", StaticAccessorType.Dot)]
        extern public static void PausePreviewClip();

        [StaticAccessor("GetAudioManager()", StaticAccessorType.Dot)]

        extern public static void ResumePreviewClip();
        ...
    }
}

またUnity2020.2以前はPlayClipというメソッド名だったそうですが、PlayPreviewClipに変更されています。

In Unity 2020.2 they changed the method names so "Clip" becomes "PreviewClip", for example "PlayPreviewClip", "IsPreviewClipPlaying", etc.

Reflected AudioUtil class for making audio based Editor Extensions - Unity Forum

やり方

リフレクションを用いてアクセスします。

private static void PlayClip(AudioClip clip)
{
    var audioUtil = typeof(UnityEditor.Editor).Assembly.GetType("UnityEditor.AudioUtil");
    var playClipMethod = audioUtil.GetMethod(
        "PlayPreviewClip",
        BindingFlags.Static | BindingFlags.Public,
        null,
        new Type[] {typeof(AudioClip), typeof(int), typeof(bool)},
        null
    );
            
    playClipMethod.Invoke(null, new object[] {clip, 0, false});
}

またUnityCsReferenceをみてみるとPauseResumeなどもあるようですね。

補足

AudioClip.Createで生成したAudioClipPlayPreviewClipの引数に渡したところ、音声が流れませんでした。

ただファイルとして出力した後、引数に渡すと一応再生することができました。(AssetDatabase.Refresh()を忘れず)

注意してください。

補足2

再生終了を検知して一時的に出力したファイルを削除したいことも多いと思います。

そういうときはIsPreviewClipPlayingを使うと良いでしょう。

private static bool CheckPreviewClipPlaying()
{
    var audioUtil = typeof(UnityEditor.Editor).Assembly.GetType("UnityEditor.AudioUtil");
    var checkPreviewClipPlayingMethod = audioUtil.GetMethod(
        "IsPreviewClipPlaying",
        BindingFlags.Static | BindingFlags.Public,
        null,
        new Type[0],
        null
    );
            
    return (bool)checkPreviewClipPlayingMethod.Invoke(null, new object[] {});
}