我正在使用一个名为 Visualizer Studio ( http://www.alteredr.com/visualizer-studio/ ) 的软件包来制作一个游戏,其中对象对音乐使用react。我的目标是让用户能够在游戏过程中随时加载歌曲。它将是独立/PC 版,而不是 WebPlayer。
我的问题是 Visualizer Studio 从场景中的音频源获取音频数据。因此,当我使用 NAudio 加载和流式传输 MP3 时,可视化工作室听不到它们,并且我的对象不会对音乐使用react。
我现在正在代码中使用 IWavePlayer。我尝试添加audio.clip = www.GetAudioClip和类似的函数来让音频剪辑加载正在播放的音乐,但无济于事。
我从这篇博客文章中获得了用于选择和流式传输 .mp3 的代码(源代码位于底部):( http://denis-potapenko.blogspot.com/2013/04/task-6-loading-mp3-audio-via-www-class.html )。目前它没有改变,因为我所做的一切都不起作用。
需要明确的是,当我从文件浏览器中选择 .mp3 时,它们会播放。我只需要它们在我的场景中通过音频源播放。拜托,一定有办法做到这一点。我已经联系了可视化工作室支持人员并在统一论坛上进行了询问,但到目前为止没有人可以提供帮助。
请记住,我并不是一个出色的程序员,因此您可能不得不为我简化答案。感谢您提前的耐心等待。无论如何,
这是我用来打开文件浏览器和流音频的代码:
using UnityEngine;
using System.Collections;
using System.IO;
using System.Runtime;
using System.Runtime.InteropServices;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Serialization;
using NAudio;
using NAudio.Wave;
public class AppRoot : MonoBehaviour
{
///////////////////////////////////////////////////////////////////////////
#region Variables
private static AppRoot mInstance = null;
private const string cLocalPath = "file://localhost/";
private IWavePlayer mWaveOutDevice;
private WaveStream mMainOutputStream;
private WaveChannel32 mVolumeStream;
#endregion
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
#region Interface
public AppRoot()
{
mInstance = this;
}
public void Start()
{
}
public void Update()
{
if(Input.GetKeyDown(KeyCode.F))
{
UnloadAudio();
LoadAudio();
}
}
public void OnGUI()
{
if (GUI.Button(new Rect(100, Screen.height - 200 + 100, Screen.width - 200, 35), "Load audio"))
{
UnloadAudio();
LoadAudio();
}
}
public void OnApplicationQuit()
{
UnloadAudio();
}
#endregion
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
#region Implementation
private void LoadAudio()
{
System.Windows.Forms.OpenFileDialog ofd = new System.Windows.Forms.OpenFileDialog();
ofd.Title = "Open audio file";
ofd.Filter = "MP3 audio (*.mp3) | *.mp3";
if (ofd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
WWW www = new WWW(cLocalPath + ofd.FileName);
Debug.Log("path = " + cLocalPath + ofd.FileName);
while (!www.isDone) { };
if (!string.IsNullOrEmpty(www.error))
{
System.Windows.Forms.MessageBox.Show("Error! Cannot open file: " + ofd.FileName + "; " + www.error);
return;
}
byte[] imageData = www.bytes;
if (!LoadAudioFromData(imageData))
{
System.Windows.Forms.MessageBox.Show("Cannot open mp3 file!");
return;
}
mWaveOutDevice.Play();
Resources.UnloadUnusedAssets();
}
}
private bool LoadAudioFromData(byte[] data)
{
try
{
MemoryStream tmpStr = new MemoryStream(data);
mMainOutputStream = new Mp3FileReader(tmpStr);
mVolumeStream = new WaveChannel32(mMainOutputStream);
mWaveOutDevice = new WaveOut();
mWaveOutDevice.Init(mVolumeStream);
return true;
}
catch (System.Exception ex)
{
Debug.LogWarning("Error! " + ex.Message);
}
return false;
}
private void UnloadAudio()
{
if (mWaveOutDevice != null)
{
mWaveOutDevice.Stop();
}
if (mMainOutputStream != null)
{
// this one really closes the file and ACM conversion
mVolumeStream.Close();
mVolumeStream = null;
// this one does the metering stream
mMainOutputStream.Close();
mMainOutputStream = null;
}
if (mWaveOutDevice != null)
{
mWaveOutDevice.Dispose();
mWaveOutDevice = null;
}
}
#endregion
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
#region Properties
private static AppRoot Instance
{
get
{
return mInstance;
}
}
#endregion
///////////////////////////////////////////////////////////////////////////
}
真诚的, 乔纳森
最佳答案
http://answers.unity3d.com/answers/1128204/view.html
将“最新”版本的 NAudio.dll 和 NAudio.WindowsMediaFormat.dll 插入您的 Resources 文件夹后,利用此代码执行您所描述的操作:
var musicInput : GameObject;
private var aud : AudioFileReader;
private var craftClip : AudioClip;
private var AudioData : float[];
private var readBuffer : float[];
private var soundSystem : AudioSource;
private var musicPath : String[];
//Check if there's a pref set for the music path. Use it AND add all the files from it
function CheckMusic()
{
var pathname = musicInput.GetComponent.<InputField>();
if(PlayerPrefs.HasKey("musicpath") == false)
{
PlayerPrefs.SetString("musicpath", "Enter Music Directory");
}
else
{
pathname.text = PlayerPrefs.GetString("musicpath");
musicPath = Directory.GetFiles(PlayerPrefs.GetString("musicpath"),"*.mp3");
}
}
function LoadSong(songToPlay : int)
{
//Download the song via WWW
var currentSong : WWW = new WWW(musicPath[songToPlay]);
//Wait for the song to download
if(currentSong.error == null)
{
//Set the title of the song
playingSong.text = Path.GetFileNameWithoutExtension(musicPath[songToPlay]);
//Parse the file with NAudio
aud = new AudioFileReader(musicPath[songToPlay]);
//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, aud.Length);
//Create a clip file the size needed to collect the sound data
craftClip = AudioClip.Create(Path.GetFileNameWithoutExtension(musicPath[songToPlay]),aud.Length,aud.WaveFormat.Channels,aud.WaveFormat.SampleRate, false);
//Fill the file with the sound data
craftClip.SetData(AudioData,0);
//Set the file as the current active sound clip
soundSystem.clip = craftClip;
}
}
我引用
The "songToPlay" variable that is passed to the function is a simple int that is acquired from the array created under the CheckMusic function. I search a chosen directory entered from a GUI Inputfield for a specific file type (MP3) which can be changed to WAV or OGG and then input those files to an array. Other code chooses the number of the song on the array to play and you can change that to anything you like. The important part is that the NAudio,dll does all the heavy lifting. All you need to do is use the aud.Read(float[] to send data to, song starting point(usually 0),length of song data (aud.length). The Float[] here is the same length as aud.length so create the float of the same length, read the file, fill the float, create the clip, then dump the float data in with AudioClip.SetData()
Right now this code works and it does the job. Downside is it takes 2-3 seconds to fill the float in this way and is a noticeable drag. It also tends to chew up memory pretty fast, but it gets the job done. Hope it helps as a starting point for those who are looking to do this. I know I needed it.
关于c# - 在 Unity 中通过音频源播放 NAudio .mp3,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19349643/