使用NAudio在Unity中创建AudioClip,在读取数据时冻结1-2秒

时间:2018-11-23 12:14:21

标签: c# unity3d audio naudio

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

在注释以下各行时,没有任何障碍。

aud =新的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));
}

}

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

非常感谢

1 个答案:

答案 0 :(得分:0)

通常使用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);
            });
        }
    });
}