Шумный аудиоклип после декодирования с base64
Я закодировал wav файл в base64 (audioClipName.txt в Ресурсах/Звуках).
ЗДЕСЬ ИСТОЧНИК ВОЛНЫ
Затем я попытался декодировать его, сделать из него AudioClip и воспроизвести его следующим образом:
public static void CreateAudioClip()
{
string s = Resources.Load<TextAsset> ("Sounds/audioClipName").text;
byte[] bytes = System.Convert.FromBase64String (s);
float[] f = ConvertByteToFloat(bytes);
AudioClip audioClip = AudioClip.Create("testSound", f.Length, 2, 44100, false, false);
audioClip.SetData(f, 0);
AudioSource as = GameObject.FindObjectOfType<AudioSource> ();
as.PlayOneShot (audioClip);
}
private static float[] ConvertByteToFloat(byte[] array)
{
float[] floatArr = new float[array.Length / 4];
for (int i = 0; i < floatArr.Length; i++)
{
if (BitConverter.IsLittleEndian)
Array.Reverse(array, i * 4, 4);
floatArr[i] = BitConverter.ToSingle(array, i * 4);
}
return floatArr;
}
Все отлично работает, за исключением того, что звук - это всего лишь один шум.
Я нашел этот здесь в переполнении стека, но ответ dosnt решил проблему.
Вот подробности о wav файле из Unity3D:
![введите описание изображения здесь]()
Кто-нибудь знает, в чем проблема?
ИЗМЕНИТЬ
Я записал двоичные файлы, один сразу после декодирования из base64, второй после окончательной конвертации и сравнил его с исходным двоичным wav файлом:
![введите описание изображения здесь]()
Как вы можете видеть, файл был закодирован правильно, потому что он просто декодирует его и записывает файл следующим образом:
string scat = Resources.Load<TextAsset> ("Sounds/test").text;
byte[] bcat = System.Convert.FromBase64String (scat);
System.IO.File.WriteAllBytes ("Assets/just_decoded.wav", bcat);
предоставили те же файлы. Все файлы имеют некоторую длину.
Но последнее неверно, поэтому проблема заключается в преобразовании в массив float. Но я не понимаю, что может быть неправильно.
EDIT:
Вот код для записи final.wav:
string scat = Resources.Load<TextAsset> ("Sounds/test").text;
byte[] bcat = System.Convert.FromBase64String (scat);
float[] f = ConvertByteToFloat(bcat);
byte[] byteArray = new byte[f.Length * 4];
Buffer.BlockCopy(f, 0, byteArray, 0, byteArray.Length);
System.IO.File.WriteAllBytes ("Assets/final.wav", byteArray);
Ответы
Ответ 1
Волновой файл, который вы пытаетесь воспроизвести (meow.wav
), имеет следующие свойства:
- PCM
- 2 канала
- 44100 Гц
- подписанный 16-битный little-endian
Ваша основная ошибка заключается в том, что вы интерпретируете двоичные данные, как если бы они уже представляли float. Это то, что делает BitConverter.ToSingle()
.
Но вам нужно сделать, чтобы создать подписанное 16-битное малоконечное значение (как указано в заголовке Wavefile) из каждых двух байтов, передать его в float и затем нормализовать его. И каждый два байта составляют образец в случае вашего файла (16-бит!), А не четыре байта. Данные немного endian (s16le), поэтому вам нужно было бы обменивать их, если хост-машина не была.
Это будет исправленная функция преобразования:
private static float[] ConvertByteToFloat(byte[] array) {
float[] floatArr = new float[array.Length / 2];
for (int i = 0; i < floatArr.Length; i++) {
floatArr[i] = ((float) BitConverter.ToInt16(array, i * 2))/32768.0;
}
return floatArr;
}
И вы должны пропустить заголовок вашего волнового файла (реальные аудиоданные начинаются со смещения 44).
Для чистого решения вам необходимо правильно интерпретировать Wave-заголовок и адаптировать свои операции в соответствии с тем, что там указано (или выпустить, если он содержит неподдерживаемые параметры).
Например, должен быть рассмотрен формат выборки (бит на выборку и конечный уровень), частоту дискретизации и количество каналов.
Ответ 2
В соответствии с документацией здесь,
Образцы должны быть плавающими в диапазоне от -1.0f до 1.0f (превышение этих пределов приведет к артефактам и поведению undefined). Счетчик выборки определяется длиной массива float, Используйте offsetSamples для записи в случайную позицию в клипе. Если длина смещения больше длины клипа, запись будет обертываться и записывать оставшиеся образцы с начала клипа.
похоже, что у вас есть именно этот эффект. Поэтому, я думаю, вам придется нормализовать массив до того, как его можно обработать.
Как вы работаете в единстве, я не уверен, какую функциональность вы можете использовать, поэтому я предоставил небольшой базовый метод расширения для массивов с плавающей запятой:
/// <summary>
/// Normalizes the values within this array.
/// </summary>
/// <param name="data">The array which holds the values to be normalized.</param>
static void Normalize(this float[] data)
{
float max = float.MinValue;
// Find maximum
for (int i = 0; i < data.Length; i++)
{
if (Math.Abs(data[i]) > max)
{
max = Math.Abs(data[i]);
}
}
// Divide all by max
for (int i = 0; i < data.Length; i++)
{
data[i] = data[i] / max;
}
}
Используйте этот метод расширения перед дальнейшей обработкой данных следующим образом:
byte[] bytes = System.Convert.FromBase64String (s);
float[] f = ConvertByteToFloat(bytes);
// Normalize the values before using them
f.Normalize();
AudioClip audioClip = AudioClip.Create("testSound", f.Length, 2, 44100, false, false);
audioClip.SetData(f, 0);