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! :slight_smile:

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…

  1. Download this .dll: NAudio.dll : Free .DLL download. - DLLme.com and import in folder Plugins

  2. Download this c# script: Dropbox - NAudioPlayer.cs - Simplify your life

  3. Download and import this Unity Asset Store: Runtime File Browser | GUI Tools | Unity Asset Store

  4. 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();   
    }
}
  1. 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