- Home /
Audioclip error using NAudio to open MP3 file on Windows
I'm using the NAudio libraries to open an MP3 file from the HardDrive, convert the byte array returned to a float array and then create an audioclip to set it to an AudioSource because i created a visualizer and i need the audio coming from inside Unity not from the SoundCard, well the problem is that i only hear strange sounds maybe because of the structure of the final audioclip but i doesn't find where the problem is or even how to identify it because i don't know too much how the sound files work, so please someone help me to fix this issue. Also, sorry if i comitted too much language errors but my mother language is spanish
using UnityEngine;
using System.Collections;
using NAudio;
using NAudio.Wave;
using System.IO;
using NAudio.MediaFoundation;
public class AbrirMP3 : MonoBehaviour {
private IWavePlayer mWaveOutDevice;
private WaveStream mMainOutputStream;
private WaveChannel32 mVolumeStream;
public GameObject Spectrum;
public int position = 0;
public int samplerate = 44100;
public float frequency = 440;
public AudioSource source1;
public int SamplesArrayFloat;
// Use this for initialization
void Start () {
}
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;
}
public static float[] ConvertByteToFloat(byte[] array) {
float[] floatArr = new float[array.Length / 4];
for (int i = 0; i < floatArr.Length; i++) {
if (System.BitConverter.IsLittleEndian) {
System.Array.Reverse(array, i * 4, 4);
}
floatArr[i] = System.BitConverter.ToSingle(array, i * 4);
}
return floatArr;
}
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("file://" + ofd.FileName);
Debug.Log("path = " + 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;
}
source1.Stop();
float[] f = ConvertByteToFloat(imageData);
SamplesArrayFloat = f.Length;
AudioClip audioClip = AudioClip.Create("testSound", f.Length, 1, 44100, false, OnAudioRead, OnAudioSetPosition);
audioClip.SetData(f, 0);
source1.clip = audioClip;
source1.Play();
Resources.UnloadUnusedAssets();
}
}
void OnAudioRead(float[] data) {
int count = 0;
while (count < data.Length) {
data[count] = Mathf.Sign(Mathf.Sin(2 * Mathf.PI * frequency * position / samplerate));
position++;
count++;
}
}
void OnAudioSetPosition(int newPosition) {
position = newPosition;
}
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;
}
}
// Update is called once per frame
void Update () {
}
}
Answer by C.IV · Jan 18, 2016 at 05:43 PM
Old question, but as it took me two days to hammer out the answer I figure it deserves one. With the "latest" version of NAudio.dll and NAudio.WindowsMediaFormat.dll inserted into your Resources folder utilize this code to do what you described:
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.
Using your code i keep getting this error... DllNotFoundException: $$anonymous$$sacm32.dll NAudio.Wave.Compression.AcmStream.$$anonymous$$gestPcmFormat (NAudio.Wave.WaveFormat compressedFormat) NAudio.Wave.Acm$$anonymous$$p3FrameDecompressor..ctor (NAudio.Wave.WaveFormat sourceFormat) NAudio.Wave.$$anonymous$$p3FileReader.CreateAcmFrameDecompressor (NAudio.Wave.WaveFormat mp3Format) NAudio.Wave.$$anonymous$$p3FileReader..ctor (System.IO.Stream inputStream, NAudio.Wave.FrameDecompressorBuilder frameDecompressorBuilder)
Your answer
![](https://koobas.hobune.stream/wayback/20220611234135im_/https://answers.unity.com/themes/thub/images/avi.jpg)
Follow this Question
Related Questions
Audio: -3db automatic attenuation on any audio playing? 0 Answers
Update and PlayOneShot (audio interval) 1 Answer
Only able to play a single sound through AudioSource. 1 Answer
How to stop footstep sound when jumping, but continue when hitting the ground? 1 Answer
Make the audio manager select from an array of sounds 1 Answer