【问题标题】:Playing NAudio .mp3 through an Audio Source in Unity在 Unity 中通过音频源播放 NAudio .mp3
【发布时间】:2013-10-21 09:26:27
【问题描述】:

我正在使用一个名为 Visualizer Studio (http://www.alteredr.com/visualizer-studio/) 的软件包来制作一个对象对音乐做出反应的游戏。我的目标是让用户能够在游戏过程中随时加载歌曲。它将是独立的/PC,而不是 WebPlayer。

我的问题是 Visualizer Studio 从场景中的音频源获取音频数据。因此,当我使用 NAudio 加载和流式传输 MP3 时,visualizer studio 听不到它们,我的对象也不会对音乐做出反应。

我现在在我的代码中使用 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
    ///////////////////////////////////////////////////////////////////////////
}

真诚地, 乔纳森

【问题讨论】:

  • @Steven 这当然是一个与 Unity 相关的问题。为什么要删除标签?
  • @Corey:不,不是。 Unity 是“.NET 的依赖注入容器”,但你说的是 Unity3d,它是“用于创建游戏的商业开发平台”。
  • @Steve 感谢您的更正,并在 :) 中添加了正确的标签

标签: c# audio unity3d mp3 naudio


【解决方案1】:

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;
     }
 }

我引用

传递给函数的“songToPlay”变量是一个简单的 int,它是从 CheckMusic 函数下创建的数组中获取的。我在从 GUI 输入字段输入的选定目录中搜​​索可以更改为 WAV 或 OGG 的特定文件类型 (MP3),然后将这些文件输入到数组中。其他代码选择要播放的数组中歌曲的编号,您可以将其更改为您喜欢的任何内容。重要的部分是 NAudio,dll 完成了所有繁重的工作。您需要做的就是使用 aud.Read(float[] 发送数据到,歌曲起点(通常为 0),歌曲数据的长度(aud.length)。这里的 Float[] 与 aud 的长度相同。所以创建相同长度的浮点数,读取文件,填充浮点数,创建剪辑,然后使用 AudioClip.SetData() 转储浮点数据

现在这段代码可以工作并且可以完成工作。缺点是需要 以这种方式填充浮子需要 2-3 秒,这是一个明显的阻力。它 也往往会很快消耗内存,但它可以完成工作。 希望它可以作为那些想要做的人的起点 这。我知道我需要它。

【讨论】:

    【解决方案2】:

    当您使用WaveOut 实例时,您正在(相对)直接在声卡上播放,在 Unity 环境之外。您需要一种将数据引入 Unity 的方法。

    我没有使用 Unity,所以这可能不是最好的答案,但是...

    您可以使用OnAudioFilterRead 将波浪数据引入场景。您可以使用它来创建程序声音,并且只需进行一些编码,它就可以连接到 NAudio 波源。这会将音频数据直接引入游戏,供您的游戏内代码处理。

    这是我发现可能有帮助的一篇文章:Procedural Audio with Unity

    【讨论】:

      【解决方案3】:
       mWaveOutDevice = new WaveOut();
      

      可能会导致问题,最好使用支持在所有非 GUI 线程中运行的 WaveOutEvent()。

       mWaveOutDevice = new WaveOutEvent();
      

      Related StackOverFlow Question

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多