Skip to content

Instantly share code, notes, and snippets.

@FleshMobProductions
Last active May 2, 2024 14:17
Show Gist options
  • Save FleshMobProductions/4521073482d9bf9c937e5b71b9c9cd80 to your computer and use it in GitHub Desktop.
Save FleshMobProductions/4521073482d9bf9c937e5b71b9c9cd80 to your computer and use it in GitHub Desktop.
Play an AudioClip asset in Unity by double clicking on it without external applications being opened
using System;
using System.Reflection;
using UnityEditor;
using UnityEditor.Callbacks;
using UnityEngine;
// Source and Credit: FREE Audio Preview Tool For Unity Tutorial (by Warped Imagination) 2022-12-05
// https://www.youtube.com/watch?v=Gd8M1Ychis8
public static class AudioPreviewer
{
// Reference for AudioUtil method information:
// https://github.com/Unity-Technologies/UnityCsReference/blob/master/Editor/Mono/Audio/Bindings/AudioUtil.bindings.cs
#if UNITY_2020_2_OR_NEWER
private static readonly string methodNamePlayClip = "PlayPreviewClip";
private static readonly string methodNameIsClipPlaying = "IsPreviewClipPlaying";
private static readonly string methodNameStopAllClips = "StopAllPreviewClips";
#else
private static readonly string methodNamePlayClip = "PlayClip";
private static readonly string methodNameIsClipPlaying = "IsClipPlaying";
private static readonly string methodNameStopAllClips = "StopAllClips";
#endif
private static AudioClip lastActiveClip;
[OnOpenAsset]
public static bool OnOpenAsset(int instanceId, int line)
{
UnityEngine.Object obj = EditorUtility.InstanceIDToObject(instanceId);
if (obj is AudioClip audioClip)
{
Debug.Log($"Open Audio Preview for \"{obj.name}\"");
PlayOrStopPreviewClip(audioClip);
return true; // Prevent Unity from further processing the opening task
}
return false; // Continue builtin handling
}
// If a clip is clicked again that is already playing, stop it. Otherwise play the new selected clip
// and stop previous clips from playing
private static void PlayOrStopPreviewClip(AudioClip audioClip)
{
Assembly unityAssembly = typeof(AudioImporter).Assembly;
Type audioUtil = unityAssembly.GetType("UnityEditor.AudioUtil");
#if UNITY_2020_2_OR_NEWER
MethodInfo isPreviewClipPlayingInfo = audioUtil.GetMethod(
methodNameIsClipPlaying,
BindingFlags.Static | BindingFlags.Public);
bool isCurrentClipPlaying = (bool)isPreviewClipPlayingInfo.Invoke(null, null) && audioClip == lastActiveClip;
#else
MethodInfo isPreviewClipPlayingInfo = audioUtil.GetMethod(
methodNameIsClipPlaying,
BindingFlags.Static | BindingFlags.Public,
null,
new System.Type[] { typeof(AudioClip) },
null);
bool isCurrentClipPlaying = (bool)isPreviewClipPlayingInfo.Invoke(null, new object[] { audioClip });
// I don't know why following line is necessary but without it, regardless of which audio file is
// double clicked the playback will always just stop instead of playing the new file
isCurrentClipPlaying &= audioClip == lastActiveClip;
#endif
MethodInfo stopAllPreviewClipsInfo = audioUtil.GetMethod(
methodNameStopAllClips, BindingFlags.Static | BindingFlags.Public);
stopAllPreviewClipsInfo.Invoke(null, null);
if (!isCurrentClipPlaying)
{
PlayPreviewClip(audioUtil, audioClip);
}
}
private static void PlayPreviewClip(Type audioUtil, AudioClip audioClip)
{
MethodInfo playPreviewClipInfo = audioUtil.GetMethod(
methodNamePlayClip,
BindingFlags.Static | BindingFlags.Public,
null,
new System.Type[] { typeof(AudioClip), typeof(Int32), typeof(Boolean) },
null);
playPreviewClipInfo.Invoke(null, new object[] { audioClip, 0, false });
lastActiveClip = audioClip;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment