2

我正在使用一个名为 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)。目前它没有改变,因为我没有尝试过任何工作。

需要明确的是,当我从文件浏览器中选择 .mp3s 时,它们会播放。我只需要它们通过我场景中的音频源播放。拜托,必须有办法做到这一点。我已经联系了可视化工作室支持并在统一论坛上询问,但到目前为止没有人可以提供帮助。

请记住,我并不是一个出色的程序员,因此您可能不得不为我回答愚蠢的问题。提前感谢您的耐心等待。反正,

这是我用来打开文件浏览器和流式传输音频的代码:

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

真诚的,乔纳森

4

3 回答 3

2

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 秒,并且是一个明显的阻力。它也倾向于很快地消耗内存,但它可以完成工作。希望它对那些希望这样做的人有所帮助。我知道我需要它。

于 2017-03-13T01:05:27.483 回答
1
 mWaveOutDevice = new WaveOut();

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

 mWaveOutDevice = new WaveOutEvent();

相关 StackOverFlow 问题

于 2014-04-25T22:16:43.367 回答
1

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

我没有与 Unity 合作过,所以这可能不是最好的答案,但是......

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

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

于 2013-10-16T13:53:34.790 回答