- Home /
Anyone been able to load an audio file from local filesystem on iOS and playback a clip?
Using WWW, I have no problem pulling an audio file off of a webserver. Using System.IO.File, I have no problem storing it (an MP3) in the app's Documents folder.
I also have no problem using WWW to load it from the local filesystem, and the data is the correct size.
The problem I am having is that WWW.getAudioClip appears to work, but the returned audio clip has 0 channels, 0 frequency, 0 samples.
The returned clip reports that it is not ready to play, whether streaming or not streaming, and that status NEVER changes...
I'm really hoping to avoid decoding MP3 by myself and stuffing it into an audio clip.
Help! :)
Answer by hkessock · Feb 04, 2014 at 10:39 PM
I have worked around this (and simultaneously given myself MP3 support on all platforms which is nice) by using parts of mp3Sharp and creating the audio clip myself and then playing it. Works great on the iPad 4 I tested with (and OSX and Windows.)
BTW, if you're going to do this yourself, remember that the decoded MP3 stream is 16-bit PCM, and Unity wants 32-bit float mapped from 0.0 to 1.0, so you need to do something similar to the following:
private AudioClip GetAudioClipFromMP3ByteArray( byte[] in_aMP3Data )
{
AudioClip l_oAudioClip = null;
Stream l_oByteStream = new MemoryStream( in_aMP3Data );
Mp3Sharp.Mp3Stream l_oMP3Stream = new Mp3Sharp.Mp3Stream( l_oByteStream );
//Get the converted stream data
MemoryStream l_oConvertedAudioData = new MemoryStream();
byte[] l_aBuffer = new byte[ 2048 ];
int l_nBytesReturned = -1;
int l_nTotalBytesReturned = 0;
while( l_nBytesReturned != 0 )
{
l_nBytesReturned = l_oMP3Stream.Read( l_aBuffer, 0, l_aBuffer.Length );
l_oConvertedAudioData.Write( l_aBuffer, 0, l_nBytesReturned );
l_nTotalBytesReturned += l_nBytesReturned;
}
Debug.Log( "MP3 file has " + l_oMP3Stream.ChannelCount + " channels with a frequency of " + l_oMP3Stream.Frequency );
byte[] l_aConvertedAudioData = l_oConvertedAudioData.ToArray();
Debug.Log( "Converted Data has " + l_aConvertedAudioData.Length + " bytes of data" );
//Convert the byte converted byte data into float form in the range of 0.0-1.0
float[] l_aFloatArray = new float[ l_aConvertedAudioData.Length / 2 ];
for( int i = 0; i < l_aFloatArray.Length; i++ )
{
if( BitConverter.IsLittleEndian )
{
//Evaluate earlier when pulling from server and/or local filesystem - not needed here
//Array.Reverse( l_aConvertedAudioData, i * 2, 2 );
}
//Yikes, remember that it is SIGNED Int16, not unsigned (spent a bit of time before realizing I screwed this up...)
l_aFloatArray[ i ] = (float)( BitConverter.ToInt16( l_aConvertedAudioData, i * 2 ) / 32768.0f );
}
//For some reason the MP3 header is readin as single channel despite it containing 2 channels of data (investigate later)
l_oAudioClip = AudioClip.Create( "MySound", l_aFloatArray.Length, 2, l_oMP3Stream.Frequency, false, false );
l_oAudioClip.SetData( l_aFloatArray, 0 );
return l_oAudioClip;
}
All of this code is hacked together over the past two hours, so there's all sorts of things missing, AND mp3Sharp is GPL'd, so I'll likely go and grab and convert JavaLayer to C# myself later so that I have an LGPL'd version.
There are some bugs in the mp3Sharp apparently as well, but hey, it's a start...
is there a documented reason why its not supported on ios? ios has hardware decoding of mp3 and the unity documentation says different. the big problem with mp3Sharp is the GPL (you have to publish your code as GPL aswell) and you have to care about the $$anonymous$$P3 License yourself if you want to use this solution in a commerial game.
Answer by DanielSRRosky1999 · Nov 25, 2019 at 04:25 AM
Download this .dll: https://www.dllme.com/dll/files/naudio_dll.html and import in folder Plugins
Download this c# script: https://www.dropbox.com/s/wks0ujanr0pm6nj/NAudioPlayer.cs?dl=0
Download and import this Unity Asset Store: https://assetstore.unity.com/packages/tools/gui/runtime-file-browser-113006
Create a c# Script, add to a gameObject, and write this lines:
using System.Collections; using System.Collections.Generic; using UnityEngine; using System.IO; using UnityEngine.UI; using System.Runtime; using System.Runtime.InteropServices; using System.Runtime.Serialization.Formatters.Binary; using System.Runtime.Serialization; using NAudio; using NAudio.Wave; using UnityEngine.Networking; using SimpleFileBrowser;
public class ReadMp3 : MonoBehaviour{
private AudioSource audioSource;
public Text pathText;
private void Start()
{
audioSource = GetComponent<AudioSource>();
}
public void ReadMp3Sounds()
{
FileBrowser.SetFilters(false, new FileBrowser.Filter("Sounds", ".mp3"));
FileBrowser.SetDefaultFilter(".mp3");
StartCoroutine(ShowLoadDialogCoroutine());
}
IEnumerator ShowLoadDialogCoroutine()
{
yield return FileBrowser.WaitForLoadDialog(false, null, "Select Sound", "Select");
pathText.text = FileBrowser.Result;
if (FileBrowser.Success)
{
byte[] SoundFile = FileBrowserHelpers.ReadBytesFromFile(FileBrowser.Result);
yield return SoundFile;
audioSource.clip = NAudioPlayer.FromMp3Data(SoundFile);
audioSource.Play();
}
}
Your game is ready for to play mp3 sounds, in Windows, Mac & Android. But on Android, I have a problem, which is this: This code works perfectly for me on Windows, however, when I export it to Android, the text correctly returns the path of the selected file in my SDCard but sounds does not play. If anyone knows how to solve this problem, I would greatly appreciate it.
Notes: When running the APK, I correctly authorize access to my storage files, And in the Editory I set External(SDCard) on WritePermission but still the selected mp3 files don't play in my APK
Your answer