Search Unity

Audio Import mp3 at runtime?

Discussion in 'Audio & Video' started by migueltuliompg, Jun 20, 2019.

  1. migueltuliompg

    migueltuliompg

    Joined:
    Feb 12, 2018
    Posts:
    63
    Hello again all!

    I'm working on an awesome editor for my rhythm-based dungeon crawler and I've got a few questions.

    First, does anyone know how to import an mp3 as an AudioClip at runtime? Maybe with NAudio?

    Right now I've got it working with NLayer...
    Code (CSharp):
    1. public static AudioClip LoadMp3(string filePath)
    2.     {
    3.         string filename = System.IO.Path.GetFileNameWithoutExtension(filePath);
    4.  
    5.         MpegFile mpegFile = new MpegFile(filePath);
    6.  
    7.         // assign samples into AudioClip
    8.         AudioClip ac = AudioClip.Create(filename,
    9.                                         (int)(mpegFile.Length / sizeof(float) / mpegFile.Channels),
    10.                                         mpegFile.Channels,
    11.                                         mpegFile.SampleRate,
    12.                                         false);
    13.         float[] data = new float[mpegFile.Length / mpegFile.Channels];
    14.  
    15.         mpegFile.ReadSamples(data, 0, data.Length);
    16.         ac.SetData(data, 0);
    17.         return ac;
    18.     }

    ...but it ends up with occasional random high pitched clicks.

    Second, How should I go about removing silence from the ends of the mp3?

    And Third, do I need a license to make an app that loads and saves mp3 files?

    Cause I found this but idk...

    From https://www.audioblog.iis.fraunhofer.com/mp3-software-patents-licenses
     
    Last edited: Jun 21, 2019
  2. YD_JMysior

    YD_JMysior

    Joined:
    Aug 4, 2016
    Posts:
    60
    Here is the code I use to load an mp3 file from Application.persistentDataPath (works for StreamingAssets too):
    Code (CSharp):
    1. private IEnumerator CoR_LoadAndPlayAudio(string audioFilePath)
    2.     {
    3.         yield return new WaitForEndOfFrame();
    4.         UnityWebRequest uwr = UnityWebRequestMultimedia.GetAudioClip(audioFilePath, AudioType.MPEG);
    5.      
    6.         uwr.uri = new Uri(uwr.uri.AbsoluteUri.Replace("http://localhost", "file://"));
    7.         uwr.url = uwr.url.Replace("http://localhost", "file://");
    8.         if (Debug.isDebugBuild) Debug.LogFormat("Loading audio file for {0} from {1} ", App.State.TextPieceToRead.Title, uwr.url);
    9.      
    10.         DownloadHandlerAudioClip dhac = uwr.downloadHandler as DownloadHandlerAudioClip;
    11.         dhac.streamAudio = true;
    12.         yield return uwr.SendWebRequest();
    13.  
    14.         if (uwr.isHttpError || uwr.isNetworkError)
    15.         {
    16.             Debug.LogErrorFormat("Could not load audio file for {0}. Error: {1}", audioFilePath,  uwr.error);
    17.             yield break;
    18.         }
    19.  
    20.         _currentClip = dhac.audioClip;
    21.      
    22.         if (_currentClip != null)
    23.         {
    24.             if (Debug.isDebugBuild) Debug.Log ("Clip load type: " + _currentClip.loadType);
    25.             if (Debug.isDebugBuild) Debug.Log ("Clip load state: " + _currentClip.loadState);
    26.             _audioSource.clip = _currentClip;
    27.             _audioSource.time = 0f;
    28.             _audioSource.Play();
    29.         }
    30. }
    As for the silence in the mp3 - I've had a similar issue a few years ago - I needed to loop short mp3 samples. Turns out it cannot be done cleanly. The mp3 needs to have that super tiny bit of silence at the beginning. If that is your case I would advise you use some other compression format.
     
  3. migueltuliompg

    migueltuliompg

    Joined:
    Feb 12, 2018
    Posts:
    63
    Awesome thanks for the code!
    I noticed that your using UnityWebRequestMultimedia though, is that usable? Cause unity Networking was deprecated and UnityWebRequestMultimedia is part of unity networking.
     
  4. YD_JMysior

    YD_JMysior

    Joined:
    Aug 4, 2016
    Posts:
    60
    It's my understanding that only the WWW class was deprecated. The UnityWebRequest is brand new (and works cool too)... Am I wrong?
     
  5. r618

    r618

    Joined:
    Jan 19, 2009
    Posts:
    1,305
    nop you're not wrong
     
  6. migueltuliompg

    migueltuliompg

    Joined:
    Feb 12, 2018
    Posts:
    63
    From this thread https://forum.unity.com/threads/unitywebrequest-vs-www.484658/

    So yeah I guess it's not. Thanks for the help!
     
  7. Kamyker

    Kamyker

    Joined:
    May 14, 2013
    Posts:
    1,091
    @YD_JMysior @migueltuliompg on what platform is it working for you? I'm getting "Streaming of 'mpeg' on this platform is not supported" on Windows all the time. (even when streaming is set to false)

    Tried also NAudio and it works in editor but doesn't in il2cpp build :/. Has anyone figured it out on Windows?
     
    xucian likes this.
  8. migueltuliompg

    migueltuliompg

    Joined:
    Feb 12, 2018
    Posts:
    63
    Mine works at least in the editor. I haven't been able to try it in a build yet cause my "standalone file browser" doesn't work in the build. I'm using Windows too.

    Hope you get it working!
     
  9. Kamyker

    Kamyker

    Joined:
    May 14, 2013
    Posts:
    1,091
    I've ended up using NLayer and so far it's working fine. Also used UniTask from https://github.com/Cysharp/UniTask to make loading run on background thread to not block game thread. Only disadvantage is slightly high memory usage but for now it's not a problem.
     
  10. DannyDan2468

    DannyDan2468

    Joined:
    Feb 23, 2014
    Posts:
    9
    Hi Kamyker,
    I'm currently facing the same problem when loading a custom MP3 with NAudio. Its working fine, except the issue, that the game is blocked when loading a new file. I looked at UniTask as you mentioned before, but I cant get it to work.
    Maybe you can provide a small example?

    Thanks for your time.
    Danny
     
  11. Kamyker

    Kamyker

    Joined:
    May 14, 2013
    Posts:
    1,091
    Use
    Code (CSharp):
    1. await UniTask.SwitchToThreadPool();
    before loading mp3 then use
    Code (CSharp):
    1. await UniTask.SwitchToMainThread();
    to sync back.
     
    DannyDan2468 likes this.
  12. DannyDan2468

    DannyDan2468

    Joined:
    Feb 23, 2014
    Posts:
    9
    Thanks for the super quick response, but sadly I still cant get it to work. I found out that not the loading of the file is the problem, but its the conversion from MP3 to WAV.

    UPDATE: Uff, I finally solved it and its now working without freezes!
    Thanks for the help Kamyker.

    Danny
     
    Last edited: Apr 29, 2020
    Kamyker likes this.