Unity中使用NAudio创建AudioClip,读取数据卡顿1-2秒
Using NAudio to create AudioClip in Unity, freezes 1-2 seconds while reading data
我目前在我的 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' on this platform is not supported 错误.这是我使用的代码。
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));
}
}
我设法通过存储最后播放的歌曲稍微改善了这种情况,这样如果用户选择播放的上一首歌曲就不会出现延迟。
非常感谢
音频通常使用 函数加载,但由于您 运行 对它有例外,所以您决定使用 NAudio。 AudioFileReader(musicPath)
和 aud.Read(AudioData, 0, (int)aud.Length)
执行时发生的冻结是有道理的,因为此构造函数和函数试图在主线程上加载音频文件并使用它们创建 PCM 数据。
因为 AudioFileReader
不是 Unity API,你应该可以在 Thread 中使用它。从另一个线程读取音频的浮点数据后,您可以回调主线程以使用 AudioClip.Create
函数创建 AudioClip,因为您不能从主线程使用此 API线程。
从 this post 获取 UnityThread
可以在主线程上轻松回调,然后查看下面的新 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 项目中使用以下代码从目录流式传输 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' on this platform is not supported 错误.这是我使用的代码。
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));
}
}
我设法通过存储最后播放的歌曲稍微改善了这种情况,这样如果用户选择播放的上一首歌曲就不会出现延迟。
非常感谢
音频通常使用 AudioFileReader(musicPath)
和 aud.Read(AudioData, 0, (int)aud.Length)
执行时发生的冻结是有道理的,因为此构造函数和函数试图在主线程上加载音频文件并使用它们创建 PCM 数据。
因为 AudioFileReader
不是 Unity API,你应该可以在 Thread 中使用它。从另一个线程读取音频的浮点数据后,您可以回调主线程以使用 AudioClip.Create
函数创建 AudioClip,因为您不能从主线程使用此 API线程。
从 this post 获取 UnityThread
可以在主线程上轻松回调,然后查看下面的新 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);
});
}
});
}