Unity中使用NAudio创建AudioClip,读取数据时卡顿1-2秒

Posted

技术标签:

【中文标题】Unity中使用NAudio创建AudioClip,读取数据时卡顿1-2秒【英文标题】:Using NAudio to create AudioClip in Unity, freezes 1-2 seconds while reading data 【发布时间】:2018-11-23 12:14:20 【问题描述】:

我目前在我的 Unity 项目中使用以下代码从目录流式传输 mp3 文件。但是它工作得很好,它在读入文件并填充浮点数时冻结。 由于这个项目是在 VR 中,所以冻结非常刺耳。我该如何解决它以便它可以在没有锁定的情况下读取?我是否尝试将其放在另一个线程上?

当注释掉以下行时,没有任何问题。

aud = new AudioFileReader(musicPath);

aud.Read(AudioData, 0, (int)aud.Length);

    public void LoadSong(string musicPath)

    //Set title of song
    songTitle = Path.GetFileNameWithoutExtension(musicPath);
    if(songTitle != currentlyPlaying && songTitle != lastPlayedTitle)
        //Parse the file with NAudio
        aud = new AudioFileReader(musicPath);

        //Create an empty float to fill with song data
        AudioData = new float[aud.Length];
        //Read the file and fill the float
        aud.Read(AudioData, 0, (int)aud.Length);

        //Create a clip file the size needed to collect the sound data
        craftClip = AudioClip.Create(songTitle, (int)aud.Length, aud.WaveFormat.Channels, aud.WaveFormat.SampleRate, false);
        //Fill the file with the sound data
        craftClip.SetData(AudioData, 0);

        if(craftClip.isReadyToPlay)
            playMusic(craftClip, songTitle);
            aud.Dispose();
         

        

        else
        
            playMusic(lastPlayedAudioFile, lastPlayedTitle);
        


我还尝试使用以下代码下载此问题https://answers.unity.com/questions/933090/wwwgetaudioclip-streaming-of-mp3-on-this-plattform.html 中提到的文件,尽管包含文件类型,但我收到不支持此平台上的“mp3”流式传输错误。这是我使用的代码。

public class AudioDownloadTest : MonoBehaviour 
public Audiosource playThis;
public AudioClip clipy;
string pathh = @"D:\TestFiles\IntheAirTonightShort.mp3";

IEnumerator Download(string pathh)
    WWW song = new WWW(pathh);
    yield return song;
    clipy = song.GetAudioClip(false,false,AudioType.MPEG);
    playThis.clip = clipy;


void Start () 
    StartCoroutine(Download(pathh));

我已经设法通过存储最后播放的歌曲来稍微改善这种情况,这样如果用户选择上一首播放的歌曲就不会延迟。

非常感谢

【问题讨论】:

能否将aud.Read(AudioData, 0, (int)aud.Length)及以下的代码注释掉,看看问题是否真的存在? 本可以发誓我已经这样做了,但也许没有:/ 它仍然会发生,但时间较短,抱歉让我再看看。 currentSong.isDone 正在正确使用机器人。您的 LoadSong 函数应该是一个协程函数,您应该放入 isDone 循环并使用 StartCoroutine 调用该函数。有关更多示例,请参阅duplicate。 删除 WWW 相关代码仍然会导致问题,因为音频文件的路径直接传递给 AudioFileReader,所以功能不需要它。我会将我的问题更改为不使用 WWW 的功能代码。 创建新的 AudioFileReader 时会出现问题,然后在读取文件时会延长。它会因音频文件的大小而异,但这些问题肯定会发生。 【参考方案1】:

Audio 通常使用 WWW.GetAudioClip 函数加载,但由于您遇到了异常,因此您决定使用 NAudio。 AudioFileReader(musicPath)aud.Read(AudioData, 0, (int)aud.Length) 执行时发生的冻结是有道理的,因为此构造函数和函数试图在主线程上加载音频文件并使用它们创建 PCM 数据。

因为AudioFileReader 不是 Unity API,您应该可以在 Thread 中使用它。从另一个线程读取音频的浮动数据后,您可以回调主线程以使用 AudioClip.Create 函数创建 AudioClip,因为您无法从主线程使用此 API。

获取UnityThread,它可以在this 帖子的主线程上轻松回调,然后查看下面的新LoadSong 函数应该是什么样子。我使用了ThreadPool,但如果您愿意,您可以在 C# 中使用任何其他线程 API。

void Awake()

    //Enable Callback on the main Thread
    UnityThread.initUnityThread();


public void LoadSong(string musicPath)

    ThreadPool.QueueUserWorkItem(delegate
    
        //Set title of song
        songTitle = Path.GetFileNameWithoutExtension(musicPath);
        if (songTitle != currentlyPlaying && songTitle != lastPlayedTitle)
        
            //Parse the file with NAudio
            aud = new AudioFileReader(musicPath);

            //Create an empty float to fill with song data
            AudioData = new float[aud.Length];
            //Read the file and fill the float
            aud.Read(AudioData, 0, (int)aud.Length);

            //Now, create the clip on the main Thread and also play it
            UnityThread.executeInUpdate(() =>
            
                //Create a clip file the size needed to collect the sound data
                craftClip = AudioClip.Create(songTitle, (int)aud.Length, aud.WaveFormat.Channels, aud.WaveFormat.SampleRate, false);
                //Fill the file with the sound data
                craftClip.SetData(AudioData, 0);

                if (craftClip.isReadyToPlay)
                
                    playMusic(craftClip, songTitle);

                    /*Disposing on main thread may also introduce freezing so do that in a Thread too*/
                    ThreadPool.QueueUserWorkItem(delegate  aud.Dispose(); );
                
            );
        
        else
        
            UnityThread.executeInUpdate(() =>
            
                playMusic(lastPlayedAudioFile, lastPlayedTitle);
            );
        
    );

【讨论】:

非常感谢!它现在只是一个可以接受的微小的昙花一现。

以上是关于Unity中使用NAudio创建AudioClip,读取数据时卡顿1-2秒的主要内容,如果未能解决你的问题,请参考以下文章

Unity3D通过Whatsapp发送AudioClip

unity AudioSource 怎么转换 AudioClip? 求大神来解救新手

与 Naudio RadioStreaming 的 Unity

Unity SKFramework框架Audio音频管理器

如何统一播放音频

音频_UnityAudio系统(1.AudioClip)