├── AudioClipPropertyDrawer.cs ├── AudioUtility.cs ├── LICENSE └── README.md /AudioClipPropertyDrawer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using UnityEditor; 4 | using UnityEngine; 5 | 6 | [CustomPropertyDrawer(typeof(AudioClip))] 7 | public class AudioClipPropertyDrawer : PropertyDrawer 8 | { 9 | private static string _scratchAudioLabel = "ScratchAudio"; 10 | private static Color _scratchAudioColor = new Color32(255, 182, 193, 255); 11 | 12 | public override float GetPropertyHeight(SerializedProperty prop, GUIContent label) 13 | { 14 | return EditorGUI.GetPropertyHeight(prop); 15 | } 16 | 17 | private Dictionary> _audioButtonStates = new Dictionary> 18 | { 19 | { ButtonState.Play, Play }, 20 | { ButtonState.Stop, Stop }, 21 | }; 22 | 23 | private enum ButtonState 24 | { 25 | Play, 26 | Stop 27 | } 28 | 29 | private static string CurrentClip; 30 | private static GUIStyle tempStyle = new GUIStyle(); 31 | 32 | 33 | public override void OnGUI(Rect position, SerializedProperty prop, GUIContent label) 34 | { 35 | EditorGUI.BeginProperty(position, label, prop); 36 | 37 | if (prop.objectReferenceValue != null) 38 | { 39 | float totalWidth = position.width; 40 | position.width = totalWidth - (totalWidth / 4); 41 | EditorGUI.PropertyField(position, prop, label, true); 42 | 43 | position.x += position.width; 44 | position.width = totalWidth / 4; 45 | DrawButton(position, prop, Array.IndexOf(AssetDatabase.GetLabels(prop.objectReferenceValue), _scratchAudioLabel) > -1 ); 46 | } 47 | else 48 | { 49 | EditorGUI.PropertyField(position, prop, label, true); 50 | } 51 | 52 | EditorGUI.EndProperty(); 53 | } 54 | 55 | private void DrawButton(Rect position, SerializedProperty prop, bool isScratchAudio) 56 | { 57 | if (prop.objectReferenceValue != null) 58 | { 59 | position.x += 4; 60 | position.width -= 5; 61 | 62 | AudioClip clip = prop.objectReferenceValue as AudioClip; 63 | 64 | Rect buttonRect = new Rect(position); 65 | buttonRect.width = 20; 66 | 67 | bool guiEnabledCache = GUI.enabled; 68 | GUI.enabled = true; 69 | 70 | Rect waveformRect = new Rect(position); 71 | waveformRect.x += 22; 72 | waveformRect.width -= 22; 73 | if (Event.current.type == EventType.Repaint) 74 | { 75 | Texture2D waveformTexture = AssetPreview.GetAssetPreview(prop.objectReferenceValue); 76 | if (waveformTexture != null) 77 | { 78 | GUI.color = isScratchAudio ? _scratchAudioColor : Color.white; 79 | tempStyle.normal.background = waveformTexture; 80 | tempStyle.Draw(waveformRect, GUIContent.none, false, false, false, false); 81 | GUI.color = Color.white; 82 | } 83 | } 84 | 85 | if (isScratchAudio) 86 | { 87 | GUIStyle style = new GUIStyle(); 88 | GUIContent content = new GUIContent("⁻ˢᶜʳᵃᵗᶜʰ⁻", "This AudioClip Asset is labeled as 'ScratchAudio'"); 89 | style.normal.textColor = _scratchAudioColor; 90 | style.alignment = TextAnchor.MiddleCenter; 91 | GUI.Box(waveformRect, content, style); 92 | } 93 | 94 | bool isPlaying = AudioUtility.IsClipPlaying(clip) && (CurrentClip == prop.propertyPath); 95 | string buttonText = ""; 96 | Action buttonAction; 97 | if (isPlaying) 98 | { 99 | EditorUtility.SetDirty(prop.serializedObject.targetObject); 100 | buttonAction = GetStateInfo(ButtonState.Stop, out buttonText); 101 | 102 | Rect progressRect = new Rect(waveformRect); 103 | float percentage = (float)AudioUtility.GetClipSamplePosition(clip) / AudioUtility.GetSampleCount(clip); 104 | float width = progressRect.width * percentage; 105 | progressRect.width = Mathf.Clamp(width, 6, width); 106 | GUI.Box(progressRect, "", "SelectionRect"); 107 | } 108 | else 109 | { 110 | buttonAction = GetStateInfo(ButtonState.Play, out buttonText); 111 | } 112 | 113 | if (GUI.Button(buttonRect, buttonText)) 114 | { 115 | AudioUtility.StopAllClips(); 116 | buttonAction(prop, clip); 117 | } 118 | 119 | GUI.enabled = guiEnabledCache; 120 | } 121 | } 122 | 123 | private static void Play(SerializedProperty prop, AudioClip clip) 124 | { 125 | CurrentClip = prop.propertyPath; 126 | AudioUtility.PlayClip(clip); 127 | } 128 | 129 | private static void Stop(SerializedProperty prop, AudioClip clip) 130 | { 131 | CurrentClip = ""; 132 | AudioUtility.StopClip(clip); 133 | } 134 | 135 | private Action GetStateInfo(ButtonState state, out string buttonText) 136 | { 137 | switch (state) 138 | { 139 | case ButtonState.Play: 140 | buttonText = "►"; 141 | break; 142 | case ButtonState.Stop: 143 | buttonText = "■"; 144 | break; 145 | default: 146 | buttonText = "?"; 147 | break; 148 | } 149 | 150 | return _audioButtonStates[state]; 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /AudioUtility.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | using UnityEngine; 4 | 5 | namespace UnityEditor { 6 | public static class AudioUtility { 7 | 8 | public static void PlayClip(AudioClip clip , int startSample , bool loop) { 9 | Assembly unityEditorAssembly = typeof(AudioImporter).Assembly; 10 | Type audioUtilClass = unityEditorAssembly.GetType("UnityEditor.AudioUtil"); 11 | MethodInfo method = audioUtilClass.GetMethod( 12 | "PlayClip", 13 | BindingFlags.Static | BindingFlags.Public, 14 | null, 15 | new System.Type[] { 16 | typeof(AudioClip), 17 | typeof(Int32), 18 | typeof(Boolean) 19 | }, 20 | null 21 | ); 22 | method.Invoke( 23 | null, 24 | new object[] { 25 | clip, 26 | startSample, 27 | loop 28 | } 29 | ); 30 | } 31 | 32 | public static void PlayClip(AudioClip clip , int startSample) { 33 | Assembly unityEditorAssembly = typeof(AudioImporter).Assembly; 34 | Type audioUtilClass = unityEditorAssembly.GetType("UnityEditor.AudioUtil"); 35 | MethodInfo method = audioUtilClass.GetMethod( 36 | "PlayClip", 37 | BindingFlags.Static | BindingFlags.Public, 38 | null, 39 | new System.Type[] { 40 | typeof(AudioClip), 41 | typeof(Int32) 42 | }, 43 | null 44 | ); 45 | method.Invoke( 46 | null, 47 | new object[] { 48 | clip, 49 | startSample 50 | } 51 | ); 52 | } 53 | 54 | public static void PlayClip(AudioClip clip) { 55 | Assembly unityEditorAssembly = typeof(AudioImporter).Assembly; 56 | Type audioUtilClass = unityEditorAssembly.GetType("UnityEditor.AudioUtil"); 57 | MethodInfo method = audioUtilClass.GetMethod( 58 | "PlayClip", 59 | BindingFlags.Static | BindingFlags.Public, 60 | null, 61 | new System.Type[] { 62 | typeof(AudioClip) 63 | }, 64 | null 65 | ); 66 | method.Invoke( 67 | null, 68 | new object[] { 69 | clip 70 | } 71 | ); 72 | } 73 | 74 | public static void StopClip(AudioClip clip) { 75 | Assembly unityEditorAssembly = typeof(AudioImporter).Assembly; 76 | Type audioUtilClass = unityEditorAssembly.GetType("UnityEditor.AudioUtil"); 77 | MethodInfo method = audioUtilClass.GetMethod( 78 | "StopClip", 79 | BindingFlags.Static | BindingFlags.Public, 80 | null, 81 | new System.Type[] { 82 | typeof(AudioClip) 83 | }, 84 | null 85 | ); 86 | method.Invoke( 87 | null, 88 | new object[] { 89 | clip 90 | } 91 | ); 92 | } 93 | 94 | public static void PauseClip(AudioClip clip) { 95 | Assembly unityEditorAssembly = typeof(AudioImporter).Assembly; 96 | Type audioUtilClass = unityEditorAssembly.GetType("UnityEditor.AudioUtil"); 97 | MethodInfo method = audioUtilClass.GetMethod( 98 | "PauseClip", 99 | BindingFlags.Static | BindingFlags.Public, 100 | null, 101 | new System.Type[] { 102 | typeof(AudioClip) 103 | }, 104 | null 105 | ); 106 | method.Invoke( 107 | null, 108 | new object[] { 109 | clip 110 | } 111 | ); 112 | } 113 | 114 | public static void ResumeClip(AudioClip clip) { 115 | Assembly unityEditorAssembly = typeof(AudioImporter).Assembly; 116 | Type audioUtilClass = unityEditorAssembly.GetType("UnityEditor.AudioUtil"); 117 | MethodInfo method = audioUtilClass.GetMethod( 118 | "ResumeClip", 119 | BindingFlags.Static | BindingFlags.Public, 120 | null, 121 | new System.Type[] { 122 | typeof(AudioClip) 123 | }, 124 | null 125 | ); 126 | method.Invoke( 127 | null, 128 | new object[] { 129 | clip 130 | } 131 | ); 132 | } 133 | 134 | public static void LoopClip(AudioClip clip , bool on) { 135 | Assembly unityEditorAssembly = typeof(AudioImporter).Assembly; 136 | Type audioUtilClass = unityEditorAssembly.GetType("UnityEditor.AudioUtil"); 137 | MethodInfo method = audioUtilClass.GetMethod( 138 | "LoopClip", 139 | BindingFlags.Static | BindingFlags.Public, 140 | null, 141 | new System.Type[] { 142 | typeof(AudioClip), 143 | typeof(bool) 144 | }, 145 | null 146 | ); 147 | method.Invoke( 148 | null, 149 | new object[] { 150 | clip, 151 | on 152 | } 153 | ); 154 | } 155 | 156 | public static bool IsClipPlaying(AudioClip clip) { 157 | Assembly unityEditorAssembly = typeof(AudioImporter).Assembly; 158 | Type audioUtilClass = unityEditorAssembly.GetType("UnityEditor.AudioUtil"); 159 | MethodInfo method = audioUtilClass.GetMethod( 160 | "IsClipPlaying", 161 | BindingFlags.Static | BindingFlags.Public 162 | ); 163 | 164 | bool playing = (bool)method.Invoke( 165 | null, 166 | new object[] { 167 | clip, 168 | } 169 | ); 170 | 171 | return playing; 172 | } 173 | 174 | public static void StopAllClips () { 175 | Assembly unityEditorAssembly = typeof(AudioImporter).Assembly; 176 | Type audioUtilClass = unityEditorAssembly.GetType("UnityEditor.AudioUtil"); 177 | MethodInfo method = audioUtilClass.GetMethod( 178 | "StopAllClips", 179 | BindingFlags.Static | BindingFlags.Public 180 | ); 181 | 182 | method.Invoke( 183 | null, 184 | null 185 | ); 186 | } 187 | 188 | public static float GetClipPosition(AudioClip clip) { 189 | Assembly unityEditorAssembly = typeof(AudioImporter).Assembly; 190 | Type audioUtilClass = unityEditorAssembly.GetType("UnityEditor.AudioUtil"); 191 | MethodInfo method = audioUtilClass.GetMethod( 192 | "GetClipPosition", 193 | BindingFlags.Static | BindingFlags.Public 194 | ); 195 | 196 | float position = (float)method.Invoke( 197 | null, 198 | new object[] { 199 | clip 200 | } 201 | ); 202 | 203 | return position; 204 | } 205 | 206 | public static int GetClipSamplePosition(AudioClip clip) { 207 | Assembly unityEditorAssembly = typeof(AudioImporter).Assembly; 208 | Type audioUtilClass = unityEditorAssembly.GetType("UnityEditor.AudioUtil"); 209 | MethodInfo method = audioUtilClass.GetMethod( 210 | "GetClipSamplePosition", 211 | BindingFlags.Static | BindingFlags.Public 212 | ); 213 | 214 | int position = (int)method.Invoke( 215 | null, 216 | new object[] { 217 | clip 218 | } 219 | ); 220 | 221 | return position; 222 | } 223 | 224 | public static void SetClipSamplePosition(AudioClip clip , int iSamplePosition) { 225 | Assembly unityEditorAssembly = typeof(AudioImporter).Assembly; 226 | Type audioUtilClass = unityEditorAssembly.GetType("UnityEditor.AudioUtil"); 227 | MethodInfo method = audioUtilClass.GetMethod( 228 | "SetClipSamplePosition", 229 | BindingFlags.Static | BindingFlags.Public 230 | ); 231 | 232 | method.Invoke( 233 | null, 234 | new object[] { 235 | clip, 236 | iSamplePosition 237 | } 238 | ); 239 | } 240 | 241 | public static int GetSampleCount(AudioClip clip) { 242 | Assembly unityEditorAssembly = typeof(AudioImporter).Assembly; 243 | Type audioUtilClass = unityEditorAssembly.GetType("UnityEditor.AudioUtil"); 244 | MethodInfo method = audioUtilClass.GetMethod( 245 | "GetSampleCount", 246 | BindingFlags.Static | BindingFlags.Public 247 | ); 248 | 249 | int samples = (int)method.Invoke( 250 | null, 251 | new object[] { 252 | clip 253 | } 254 | ); 255 | 256 | return samples; 257 | } 258 | 259 | public static int GetChannelCount(AudioClip clip) { 260 | Assembly unityEditorAssembly = typeof(AudioImporter).Assembly; 261 | Type audioUtilClass = unityEditorAssembly.GetType("UnityEditor.AudioUtil"); 262 | MethodInfo method = audioUtilClass.GetMethod( 263 | "GetChannelCount", 264 | BindingFlags.Static | BindingFlags.Public 265 | ); 266 | 267 | int channels = (int)method.Invoke( 268 | null, 269 | new object[] { 270 | clip 271 | } 272 | ); 273 | 274 | return channels; 275 | } 276 | 277 | public static int GetBitRate(AudioClip clip) { 278 | Assembly unityEditorAssembly = typeof(AudioImporter).Assembly; 279 | Type audioUtilClass = unityEditorAssembly.GetType("UnityEditor.AudioUtil"); 280 | MethodInfo method = audioUtilClass.GetMethod( 281 | "GetChannelCount", 282 | BindingFlags.Static | BindingFlags.Public 283 | ); 284 | 285 | int bitRate = (int)method.Invoke( 286 | null, 287 | new object[] { 288 | clip 289 | } 290 | ); 291 | 292 | return bitRate; 293 | } 294 | 295 | public static int GetBitsPerSample(AudioClip clip) { 296 | Assembly unityEditorAssembly = typeof(AudioImporter).Assembly; 297 | Type audioUtilClass = unityEditorAssembly.GetType("UnityEditor.AudioUtil"); 298 | MethodInfo method = audioUtilClass.GetMethod( 299 | "GetBitsPerSample", 300 | BindingFlags.Static | BindingFlags.Public 301 | ); 302 | 303 | int bits = (int)method.Invoke( 304 | null, 305 | new object[] { 306 | clip 307 | } 308 | ); 309 | 310 | return bits; 311 | } 312 | 313 | public static int GetFrequency(AudioClip clip) { 314 | Assembly unityEditorAssembly = typeof(AudioImporter).Assembly; 315 | Type audioUtilClass = unityEditorAssembly.GetType("UnityEditor.AudioUtil"); 316 | MethodInfo method = audioUtilClass.GetMethod( 317 | "GetFrequency", 318 | BindingFlags.Static | BindingFlags.Public 319 | ); 320 | 321 | int frequency = (int)method.Invoke( 322 | null, 323 | new object[] { 324 | clip 325 | } 326 | ); 327 | 328 | return frequency; 329 | } 330 | 331 | public static int GetSoundSize(AudioClip clip) { 332 | Assembly unityEditorAssembly = typeof(AudioImporter).Assembly; 333 | Type audioUtilClass = unityEditorAssembly.GetType("UnityEditor.AudioUtil"); 334 | MethodInfo method = audioUtilClass.GetMethod( 335 | "GetSoundSize", 336 | BindingFlags.Static | BindingFlags.Public 337 | ); 338 | 339 | int size = (int)method.Invoke( 340 | null, 341 | new object[] { 342 | clip 343 | } 344 | ); 345 | 346 | return size; 347 | } 348 | 349 | public static Texture2D GetWaveForm(AudioClip clip , int channel , float width , float height) { 350 | Assembly unityEditorAssembly = typeof(AudioImporter).Assembly; 351 | Type audioUtilClass = unityEditorAssembly.GetType("UnityEditor.AudioUtil"); 352 | MethodInfo method = audioUtilClass.GetMethod( 353 | "GetWaveForm", 354 | BindingFlags.Static | BindingFlags.Public 355 | ); 356 | 357 | string path = AssetDatabase.GetAssetPath(clip); 358 | AudioImporter importer = (AudioImporter)AssetImporter.GetAtPath(path); 359 | 360 | Texture2D texture = (Texture2D)method.Invoke( 361 | null, 362 | new object[] { 363 | clip, 364 | importer, 365 | channel, 366 | width, 367 | height 368 | } 369 | ); 370 | 371 | return texture; 372 | } 373 | 374 | public static Texture2D GetWaveFormFast(AudioClip clip , int channel , int fromSample , int toSample, float width , float height) { 375 | Assembly unityEditorAssembly = typeof(AudioImporter).Assembly; 376 | Type audioUtilClass = unityEditorAssembly.GetType("UnityEditor.AudioUtil"); 377 | MethodInfo method = audioUtilClass.GetMethod( 378 | "GetWaveFormFast", 379 | BindingFlags.Static | BindingFlags.Public 380 | ); 381 | 382 | Texture2D texture = (Texture2D)method.Invoke( 383 | null, 384 | new object[] { 385 | clip, 386 | channel, 387 | fromSample, 388 | toSample, 389 | width, 390 | height 391 | } 392 | ); 393 | 394 | return texture; 395 | } 396 | 397 | public static void ClearWaveForm(AudioClip clip) { 398 | Assembly unityEditorAssembly = typeof(AudioImporter).Assembly; 399 | Type audioUtilClass = unityEditorAssembly.GetType("UnityEditor.AudioUtil"); 400 | MethodInfo method = audioUtilClass.GetMethod( 401 | "ClearWaveForm", 402 | BindingFlags.Static | BindingFlags.Public 403 | ); 404 | 405 | method.Invoke( 406 | null, 407 | new object[] { 408 | clip 409 | } 410 | ); 411 | } 412 | 413 | public static bool HasPreview(AudioClip clip) { 414 | Assembly unityEditorAssembly = typeof(AudioImporter).Assembly; 415 | Type audioUtilClass = unityEditorAssembly.GetType("UnityEditor.AudioUtil"); 416 | MethodInfo method = audioUtilClass.GetMethod( 417 | "GetSoundSize", 418 | BindingFlags.Static | BindingFlags.Public 419 | ); 420 | 421 | bool hasPreview = (bool)method.Invoke( 422 | null, 423 | new object[] { 424 | clip 425 | } 426 | ); 427 | 428 | return hasPreview; 429 | } 430 | 431 | public static bool IsCompressed(AudioClip clip) { 432 | Assembly unityEditorAssembly = typeof(AudioImporter).Assembly; 433 | Type audioUtilClass = unityEditorAssembly.GetType("UnityEditor.AudioUtil"); 434 | MethodInfo method = audioUtilClass.GetMethod( 435 | "IsCompressed", 436 | BindingFlags.Static | BindingFlags.Public 437 | ); 438 | 439 | bool isCompressed = (bool)method.Invoke( 440 | null, 441 | new object[] { 442 | clip 443 | } 444 | ); 445 | 446 | return isCompressed; 447 | } 448 | 449 | public static bool IsStramed(AudioClip clip) { 450 | Assembly unityEditorAssembly = typeof(AudioImporter).Assembly; 451 | Type audioUtilClass = unityEditorAssembly.GetType("UnityEditor.AudioUtil"); 452 | MethodInfo method = audioUtilClass.GetMethod( 453 | "IsStramed", 454 | BindingFlags.Static | BindingFlags.Public 455 | ); 456 | 457 | bool isStreamed = (bool)method.Invoke( 458 | null, 459 | new object[] { 460 | clip 461 | } 462 | ); 463 | 464 | return isStreamed; 465 | } 466 | 467 | public static double GetDuration(AudioClip clip) { 468 | Assembly unityEditorAssembly = typeof(AudioImporter).Assembly; 469 | Type audioUtilClass = unityEditorAssembly.GetType("UnityEditor.AudioUtil"); 470 | MethodInfo method = audioUtilClass.GetMethod( 471 | "GetDuration", 472 | BindingFlags.Static | BindingFlags.Public 473 | ); 474 | 475 | double duration = (double)method.Invoke( 476 | null, 477 | new object[] { 478 | clip 479 | } 480 | ); 481 | 482 | return duration; 483 | } 484 | 485 | public static int GetFMODMemoryAllocated() { 486 | Assembly unityEditorAssembly = typeof(AudioImporter).Assembly; 487 | Type audioUtilClass = unityEditorAssembly.GetType("UnityEditor.AudioUtil"); 488 | MethodInfo method = audioUtilClass.GetMethod( 489 | "GetFMODMemoryAllocated", 490 | BindingFlags.Static | BindingFlags.Public 491 | ); 492 | 493 | int memoryAllocated = (int)method.Invoke( 494 | null, 495 | null 496 | ); 497 | 498 | return memoryAllocated; 499 | } 500 | 501 | public static float GetFMODCPUUsage() { 502 | Assembly unityEditorAssembly = typeof(AudioImporter).Assembly; 503 | Type audioUtilClass = unityEditorAssembly.GetType("UnityEditor.AudioUtil"); 504 | MethodInfo method = audioUtilClass.GetMethod( 505 | "GetFMODCPUUsage", 506 | BindingFlags.Static | BindingFlags.Public 507 | ); 508 | 509 | float cpuUsage = (float)method.Invoke( 510 | null, 511 | null 512 | ); 513 | 514 | return cpuUsage; 515 | } 516 | 517 | public static bool Is3D(AudioClip clip) { 518 | Assembly unityEditorAssembly = typeof(AudioImporter).Assembly; 519 | Type audioUtilClass = unityEditorAssembly.GetType("UnityEditor.AudioUtil"); 520 | MethodInfo method = audioUtilClass.GetMethod( 521 | "Is3D", 522 | BindingFlags.Static | BindingFlags.Public 523 | ); 524 | 525 | bool is3D = (bool)method.Invoke( 526 | null, 527 | new object[] { 528 | clip 529 | } 530 | ); 531 | 532 | return is3D; 533 | } 534 | 535 | public static bool IsMovieAudio(AudioClip clip) { 536 | Assembly unityEditorAssembly = typeof(AudioImporter).Assembly; 537 | Type audioUtilClass = unityEditorAssembly.GetType("UnityEditor.AudioUtil"); 538 | MethodInfo method = audioUtilClass.GetMethod( 539 | "IsMovieAudio", 540 | BindingFlags.Static | BindingFlags.Public 541 | ); 542 | 543 | bool isMovieAudio = (bool)method.Invoke( 544 | null, 545 | new object[] { 546 | clip 547 | } 548 | ); 549 | 550 | return isMovieAudio; 551 | } 552 | 553 | public static bool IsMOD(AudioClip clip) { 554 | Assembly unityEditorAssembly = typeof(AudioImporter).Assembly; 555 | Type audioUtilClass = unityEditorAssembly.GetType("UnityEditor.AudioUtil"); 556 | MethodInfo method = audioUtilClass.GetMethod( 557 | "IsMOD", 558 | BindingFlags.Static | BindingFlags.Public 559 | ); 560 | 561 | bool isMOD = (bool)method.Invoke( 562 | null, 563 | new object[] { 564 | clip 565 | } 566 | ); 567 | 568 | return isMOD; 569 | } 570 | 571 | public static int GetMODChannelCount() { 572 | Assembly unityEditorAssembly = typeof(AudioImporter).Assembly; 573 | Type audioUtilClass = unityEditorAssembly.GetType("UnityEditor.AudioUtil"); 574 | MethodInfo method = audioUtilClass.GetMethod( 575 | "GetMODChannelCount", 576 | BindingFlags.Static | BindingFlags.Public 577 | ); 578 | 579 | int channels = (int)method.Invoke( 580 | null, 581 | null 582 | ); 583 | 584 | return channels; 585 | } 586 | 587 | public static AnimationCurve GetLowpassCurve(AudioLowPassFilter lowPassFilter) { 588 | Assembly unityEditorAssembly = typeof(AudioImporter).Assembly; 589 | Type audioUtilClass = unityEditorAssembly.GetType("UnityEditor.AudioUtil"); 590 | MethodInfo method = audioUtilClass.GetMethod( 591 | "GetLowpassCurve", 592 | BindingFlags.Static | BindingFlags.Public 593 | ); 594 | 595 | AnimationCurve curve = (AnimationCurve)method.Invoke( 596 | null, 597 | new object[] { 598 | lowPassFilter 599 | } 600 | ); 601 | 602 | return curve; 603 | } 604 | 605 | public static Vector3 GetListenerPos() { 606 | Assembly unityEditorAssembly = typeof(AudioImporter).Assembly; 607 | Type audioUtilClass = unityEditorAssembly.GetType("UnityEditor.AudioUtil"); 608 | MethodInfo method = audioUtilClass.GetMethod( 609 | "GetListenerPos", 610 | BindingFlags.Static | BindingFlags.Public 611 | ); 612 | 613 | Vector3 position = (Vector3)method.Invoke( 614 | null, 615 | null 616 | ); 617 | 618 | return position; 619 | } 620 | 621 | public static void UpdateAudio() { 622 | Assembly unityEditorAssembly = typeof(AudioImporter).Assembly; 623 | Type audioUtilClass = unityEditorAssembly.GetType("UnityEditor.AudioUtil"); 624 | MethodInfo method = audioUtilClass.GetMethod( 625 | "UpdateAudio", 626 | BindingFlags.Static | BindingFlags.Public 627 | ); 628 | 629 | method.Invoke( 630 | null, 631 | null 632 | ); 633 | } 634 | 635 | public static void SetListenerTransform(Transform t) { 636 | Assembly unityEditorAssembly = typeof(AudioImporter).Assembly; 637 | Type audioUtilClass = unityEditorAssembly.GetType("UnityEditor.AudioUtil"); 638 | MethodInfo method = audioUtilClass.GetMethod( 639 | "SetListenerTransform", 640 | BindingFlags.Static | BindingFlags.Public 641 | ); 642 | 643 | method.Invoke( 644 | null, 645 | new object[] { 646 | t 647 | } 648 | ); 649 | } 650 | 651 | public static AudioType GetClipType(AudioClip clip) { 652 | Assembly unityEditorAssembly = typeof(AudioImporter).Assembly; 653 | Type audioUtilClass = unityEditorAssembly.GetType("UnityEditor.AudioUtil"); 654 | MethodInfo method = audioUtilClass.GetMethod( 655 | "GetClipType", 656 | BindingFlags.Static | BindingFlags.Public 657 | ); 658 | 659 | AudioType type = (AudioType)method.Invoke( 660 | null, 661 | new object[] { 662 | clip 663 | } 664 | ); 665 | 666 | return type; 667 | } 668 | 669 | public static AudioType GetPlatformConversionType(AudioType inType , BuildTargetGroup targetGroup , AudioImporterFormat format) { 670 | Assembly unityEditorAssembly = typeof(AudioImporter).Assembly; 671 | Type audioUtilClass = unityEditorAssembly.GetType("UnityEditor.AudioUtil"); 672 | MethodInfo method = audioUtilClass.GetMethod( 673 | "GetPlatformConversionType", 674 | BindingFlags.Static | BindingFlags.Public 675 | ); 676 | 677 | AudioType type = (AudioType)method.Invoke( 678 | null, 679 | new object[] { 680 | inType, 681 | targetGroup, 682 | format 683 | } 684 | ); 685 | 686 | return type; 687 | } 688 | 689 | public static bool HaveAudioCallback(MonoBehaviour behaviour) { 690 | Assembly unityEditorAssembly = typeof(AudioImporter).Assembly; 691 | Type audioUtilClass = unityEditorAssembly.GetType("UnityEditor.AudioUtil"); 692 | MethodInfo method = audioUtilClass.GetMethod( 693 | "HaveAudioCallback", 694 | BindingFlags.Static | BindingFlags.Public 695 | ); 696 | 697 | bool hasCallback = (bool)method.Invoke( 698 | null, 699 | new object[] { 700 | behaviour 701 | } 702 | ); 703 | 704 | return hasCallback; 705 | } 706 | 707 | public static int GetCustomFilterChannelCount(MonoBehaviour behaviour) { 708 | Assembly unityEditorAssembly = typeof(AudioImporter).Assembly; 709 | Type audioUtilClass = unityEditorAssembly.GetType("UnityEditor.AudioUtil"); 710 | MethodInfo method = audioUtilClass.GetMethod( 711 | "GetCustomFilterChannelCount", 712 | BindingFlags.Static | BindingFlags.Public 713 | ); 714 | 715 | int channels = (int)method.Invoke( 716 | null, 717 | new object[] { 718 | behaviour 719 | } 720 | ); 721 | 722 | return channels; 723 | } 724 | 725 | public static int GetCustomFilterProcessTime(MonoBehaviour behaviour) { 726 | Assembly unityEditorAssembly = typeof(AudioImporter).Assembly; 727 | Type audioUtilClass = unityEditorAssembly.GetType("UnityEditor.AudioUtil"); 728 | MethodInfo method = audioUtilClass.GetMethod( 729 | "GetCustomFilterProcessTime", 730 | BindingFlags.Static | BindingFlags.Public 731 | ); 732 | 733 | int processTime = (int)method.Invoke( 734 | null, 735 | new object[] { 736 | behaviour 737 | } 738 | ); 739 | 740 | return processTime; 741 | } 742 | 743 | public static float GetCustomFilterMaxIn(MonoBehaviour behaviour , int channel) { 744 | Assembly unityEditorAssembly = typeof(AudioImporter).Assembly; 745 | Type audioUtilClass = unityEditorAssembly.GetType("UnityEditor.AudioUtil"); 746 | MethodInfo method = audioUtilClass.GetMethod( 747 | "GetCustomFilterMaxIn", 748 | BindingFlags.Static | BindingFlags.Public 749 | ); 750 | 751 | float maxIn = (float)method.Invoke( 752 | null, 753 | new object[] { 754 | behaviour, 755 | channel 756 | } 757 | ); 758 | 759 | return maxIn; 760 | } 761 | 762 | public static float GetCustomFilterMaxOut(MonoBehaviour behaviour , int channel) { 763 | Assembly unityEditorAssembly = typeof(AudioImporter).Assembly; 764 | Type audioUtilClass = unityEditorAssembly.GetType("UnityEditor.AudioUtil"); 765 | MethodInfo method = audioUtilClass.GetMethod( 766 | "GetCustomFilterMaxOut", 767 | BindingFlags.Static | BindingFlags.Public 768 | ); 769 | 770 | float maxOut = (float)method.Invoke( 771 | null, 772 | new object[] { 773 | behaviour, 774 | channel 775 | } 776 | ); 777 | 778 | return maxOut; 779 | } 780 | } 781 | } 782 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Unity3D_PropertyDrawer_AudioClip 2 | Draws a play button and waveform preview for serialized AudioClip fields 3 | 4 | ![AudioClip PropertyDrawer Inspector](https://i.imgur.com/9kHBo6c.png "AudioClip PropertyDrawer Inspector") 5 | 6 | If you label your Audio Asset "ScratchAudio" the property will draw with a red overlay and text indicating it's ⁻ˢᶜʳᵃᵗᶜʰ⁻ state. 7 | 8 | _Note: Make sure to place both scripts (AudioClipPropertyDrawer.cs and AudioUtilities.cs) in a folder named "Editor" in your project._ 9 | --------------------------------------------------------------------------------