Search Unity

Reflected AudioUtil class for making audio based Editor Extensions

Discussion in 'Immediate Mode GUI (IMGUI)' started by Rtyper, Mar 7, 2015.

  1. Rtyper

    Rtyper

    Joined:
    Aug 7, 2010
    Posts:
    452
    Hi guys,
    I've been working on an editor extension recently that required the ability to play/pause/stop and get waveforms of various AudioClips within the editor. I wanted the cleanest way of doing this possible (so no creating hidden GameObjects etc) so I went searching online, and found this thread.

    So, after shamelessly stealing A Shim.3D's code snippet there, I wrote a method to find all the static methods in that AudioUtil class, and started using that code to get access to the ones I needed.
    The end result is this, AudioUtility.cs. It has every public static method from AudioUtil available in it. Hopefully some other people will be able to get some use out of these features too!

    Simply copy it into your project, and import the "UnityEditor" namespace in your script to use it.

    Cheers!
     

    Attached Files:

    leni8ec, g__b, nzhangaudio and 3 others like this.
  2. jhample

    jhample

    Joined:
    Jul 7, 2012
    Posts:
    47
    Thank you soooo much! I am working on a new editor for a rhythm game and this is amazingly helpful!
     
  3. Rtyper

    Rtyper

    Joined:
    Aug 7, 2010
    Posts:
    452
    No problem, glad someone has some use for it :)
     
  4. jhample

    jhample

    Joined:
    Jul 7, 2012
    Posts:
    47
    I am having an issue with starting a song at a specific point. It seems to always start at the beginning. Is this a bug, or am I not using it properly?
    Code (CSharp):
    1. AudioUtility.PlayClip(song.song, songStart, false);
    Where song.song is an Audioclip and songStart is a value between 0 and AudioUtility.GetSampleCount()
     
  5. Rtyper

    Rtyper

    Joined:
    Aug 7, 2010
    Posts:
    452
    Unfortunately that does seem to be a bug, I haven't had any luck getting that to work either. I included them in the class anyway just in case Unity fixes it in future.

    The best solution I've got so far is just playing it normally, then using SetClipSamplePosition straight afterwards. Seems to work just as well, but it's not quite as clean.
     
  6. jhample

    jhample

    Joined:
    Jul 7, 2012
    Posts:
    47
    I didn't even think to try that. That works perfect.
     
  7. winxalex

    winxalex

    Joined:
    Jun 29, 2014
    Posts:
    166
    1. Code (CSharp):
      1.   sampleStart = (int)Math.Ceiling (audioClip.samples * ((__sequence.timeCurrent - node.startTime) / audioClip.length));//do your calculation
      2.                    
      3.                                  AudioUtilW.PlayClip (audioClip, 0, node.loop);//startSample doesn't work in this function????
      4.                                                              AudioUtilW.SetClipSamplePosition (audioClip, sampleStart);
    Problem that I couldn't solve was with Stop and StopAll not working when you have started more clips to play at once. Seem stoping last one only.
     
  8. Rtyper

    Rtyper

    Joined:
    Aug 7, 2010
    Posts:
    452
    Yeah, I've come across similar problems (though only in Unity 5) with clips playing. It also sometimes breaks altogether for me, and stops the Unity editor from playing any audio at all until it's restarted. Unfortunately, I suppose this is stuff we just have to put up with unless Unity decides to make the AudioUtil class public and supports it.
     
  9. winxalex

    winxalex

    Joined:
    Jun 29, 2014
    Posts:
    166
    Or some Unity inhous developer tell us about secret sauce. :). I notice that above happen even in Unity Audio Inspector where they use StopAll. You can play some sound outside and thru Audio Inspector in parallel. Then try to StopAll... I've played Vidoe Sound and play good when not played in parallel with some other sound then sample gone crazy.

     
  10. sugamo

    sugamo

    Joined:
    Nov 5, 2014
    Posts:
    1
    Hello. I greatly appreciate your sharing AudioUtility.cs!

    I use this for drawing wave-form of audioclip and play audio like preview window.

    However, in unity5.4, getting wave-form texture method disappear!
    If you know how to easily draw wave-form of audioclip without GetWaveFormFast() , please tell me..
     
  11. Setsuki

    Setsuki

    Joined:
    Aug 21, 2012
    Posts:
    31
    3 years later and this still helps, once the few quirks are known (can't stop an audio when multiple are played, "start sample" is basically useless but SetClipSamplePosition fixes it, etc...) your class is really helpful, thanks !
     
    Hunter_Bobeck likes this.
  12. Orion

    Orion

    Joined:
    Mar 31, 2008
    Posts:
    261
    This is great! Is there a way to change the playback volume, though?
     
  13. Foriero

    Foriero

    Joined:
    Jan 24, 2012
    Posts:
    584
    Hi, has anyone reflected AudioUtil.cs for 2019.x? Seems like there are some changes and code above does not work. Or parts of it do not work. Thank you, Marek.
     
  14. Rtyper

    Rtyper

    Joined:
    Aug 7, 2010
    Posts:
    452
    I haven't really updated this in a long time - I switched to using a hidden GameObject with an AudioSource on a long time ago (round about when Unity 5 was new I think) because of problems with sounds refusing to stop and then cutting out entirely! They also removed the waveform texture methods in 5.5 or 5.6 I think. You're better off going with the GameObject method these days - you can set its hideFlags from a script so it doesn't get saved with your scene or show up in the hierarchy.
     
  15. neoRiley

    neoRiley

    Joined:
    Dec 12, 2008
    Posts:
    162
    also, should anyone else be puzzled for the first time on this, you have to get the percentage of where you want to play based on the number of samples in the clip.

    Example:
    I want to play at a position that's 50% of the way through the clip:

    First, get the number of samples:
    var samples = AudioUtility.GetSampleCount(source.clip);


    Then, simply multiply your percentage against that:
    int playFrom = Mathf.FloorToInt(samples * 0.5f);


    Then, use it together:
    Code (CSharp):
    1. AudioUtility.PlayClip(source.clip, playFrom, false);
    2. AudioUtility.SetClipSamplePosition(source.clip, playFrom);
    As a side note, I simply added this line to the 2 PlayClip() methods in AudioUtility.cs to just have it do it for me :)
    Code (CSharp):
    1.  
    2. public static void PlayClip(AudioClip clip, int startSample, bool loop)
    3. {
    4.     Assembly unityEditorAssembly = typeof(AudioImporter).Assembly;
    5.     Type audioUtilClass = unityEditorAssembly.GetType("UnityEditor.AudioUtil");
    6.     MethodInfo method = audioUtilClass.GetMethod(
    7.         "PlayClip",
    8.         BindingFlags.Static | BindingFlags.Public,
    9.         null,
    10.         new System.Type[] {
    11.         typeof(AudioClip),
    12.         typeof(Int32),
    13.         typeof(Boolean)
    14.     },
    15.     null
    16.     );
    17.     method.Invoke(
    18.         null,
    19.         new object[] {
    20.         clip,
    21.         startSample,
    22.         loop
    23.     }
    24.     );
    25.  
    26.     SetClipSamplePosition(clip, startSample);
    27. }
    28.  
    29. public static void PlayClip(AudioClip clip, int startSample)
    30. {
    31.     PlayClip(clip, startSample, false);
    32. }
    33.  
    34. public static void PlayClip(AudioClip clip)
    35. {
    36.     PlayClip(clip, 0, false);
    37. }
    38.  
    [UPDATE] It seems that in 2019.x the other 2 PlayClip methods are broken, so I've updated my classes to the above. Works great!

    Have a bandit day!
     
    Last edited: Mar 4, 2020
    nzhangaudio likes this.
  16. michelm

    michelm

    Joined:
    Jul 2, 2012
    Posts:
    15
    In Unity 2020.2 they changed the method names so "Clip" becomes "PreviewClip", for example "PlayPreviewClip", "IsPreviewClipPlaying", etc.

    https://github.com/Unity-Technologi...Mono/Audio/Bindings/AudioUtil.bindings.cs#L30

    Also, when invoking the method the null should come after the object, I think.

    Code (CSharp):
    1. return (bool)method.Invoke(
    2.                 new object[] {
    3.                     clip
    4.                 },
    5.                 null
    6.             );
     
    Kronus, leni8ec, AndyKorth and 5 others like this.
  17. RageByte

    RageByte

    Joined:
    Jul 2, 2017
    Posts:
    34
    This is working really great. But is there a way to set the volume?
     
  18. RageByte

    RageByte

    Joined:
    Jul 2, 2017
    Posts:
    34
    Gave up on this in the end due to unreliability.
     
  19. Foriero

    Foriero

    Joined:
    Jan 24, 2012
    Posts:
    584
    Yes, Unity, please give use exposed API. Thank you.
     
    BekaFndr likes this.
  20. ThePilgrim

    ThePilgrim

    Joined:
    Apr 25, 2013
    Posts:
    17
    I am also looking for a way to control volume through this. Here is the AudioUtil class, and it doesn't look like there is a way.
     
  21. Kronus

    Kronus

    Joined:
    Oct 30, 2021
    Posts:
    3