0

(continuing to the question here... )

After some research, I have got the following:

private float[] Normalize(float[] data)  {
    float max = float.MinValue;
    for (int i = 0; i < data.Length; i++){
        if (System.Math.Abs(data[i]) > max) max = System.Math.Abs(data[i]);
    }
    for (int i = 0; i < data.Length; i++) data[i] = data[i] / max;
    return data;
}

private 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 Normalize(floatArr);
}
byte[] bytes = System.Convert.FromBase64String(data);
float[] f = ConvertByteToFloat(bytes);
qa[i] = AudioClip.Create("qjAudio", f.Length, 2, 44100, false);
qa[i].SetData(f,0);

However, all I heard was some random noise.

Someone suggested converting it to a file first:

[SerializeField] private AudioSource _audioSource;
private void Start()
{
    StartCoroutine(ConvertBase64ToAudioClip(EXAMPLE_BASE64_MP3_STRING, _audioSource));
}
    
IEnumerator ConvertBase64ToAudioClip(string base64EncodedMp3String, AudioSource audioSource)
{
    var audioBytes = Convert.FromBase64String(base64EncodedMp3String);
    var tempPath = Application.persistentDataPath + "tmpMP3Base64.mp3";
    File.WriteAllBytes(tempPath, audioBytes);
    UnityWebRequest request = UnityWebRequestMultimedia.GetAudioClip(tempPath, AudioType.MPEG);
    yield return request.SendWebRequest();
    if (request.result.Equals(UnityWebRequest.Result.ConnectionError))
        Debug.LogError(request.error);
    else
    {
        audioSource.clip = DownloadHandlerAudioClip.GetContent(request);
        audioSource.Play();
    }

    File.Delete(tempPath);
}

However, for this to work on Android devices, I will need to request Android permissions, which can discourage players to try my game. It will also create a lot of sophistication as I will need to handle cases when the player has already rejected them once so that the request dialogs won't appear again.

How can I correctly convert a base64 mp3 string into AudioClip without resorting to using the physical storage?

Chong Lip Phang
  • 8,755
  • 5
  • 65
  • 100
  • You can use a memory stream (https://docs.unity.cn/540/Documentation/ScriptReference/WWW.GetAudioClip.html) which does not use file system. – jdweng Feb 11 '23 at 10:57
  • @jdweng Could you please elaborate? I wish to open a 100-point bounty if I can now. – Chong Lip Phang Feb 11 '23 at 12:53
  • You need to find out the type of audio. After converting to bytes the beginning of the data is an ASCII header that tells the type of audio, You need to get the type. Then find online a way of read the audio type from bytes (or steam), You can convert the bytes to a memory stream using following : MemoryStream ms = new MemoryStream(bytes); – jdweng Feb 11 '23 at 15:46

1 Answers1

0

The code should be simple an not require any byte swapping. See following : https://docs.unity.cn/540/Documentation/ScriptReference/WWW.GetAudioClip.html

            byte[] bytes = System.Convert.FromBase64String(data);
            MemoryStream ms = new MemoryStream(bytes);
            ms.Position = 0;
            AudioClip GetAudioClip(bool threeD, bool stream, AudioType.MPEG);
jdweng
  • 33,250
  • 2
  • 15
  • 20