Много шума при воспроизведении звука AudioSource (Unity)?
Мне нужно проиграть .mp3 файл (длительность ~1мин), но нужно проиграть его как byte[] которые я получаю от нативной либы. То есть флоу выглядит так native decoder(MediaFoundataion) -> ConvertFromByteToFloat -> Playback(Unity).
Вот метод который я использую для конвертации
private static float[] Convert16BitByteArrayToAudioClipData(byte[] source)
{
float[] data = new float[source.Length];
for (int i = 0; i < source.Length; i++)
{
data[i] = ((float)source[i] / Int16.MaxValue);
}
return data;
}
И вот метод котой проигрывает звук
void playSound()
{
// create audiosource object and audio clip
if (audioSource == null)
{
audioSource = gameObject.AddComponent<AudioSource>();
audioSource.pitch = audioPitch;
audioSource.volume = audioVolume;
audioSource.loop = audioLoop;
}
((StreamCompositeWithAudio) stream).GetCharacteristics(
ref mAudioSampleRate,
ref bitsPerSample,
ref mAudioChannels,
ref mAudioLengthSamples
);
if (audioClip == null && audioSource != null)
{
audioClip = AudioClip.Create("videoAudio", mAudioLengthSamples * 200 /*for test*/, (int)mAudioChannels, (int)mAudioSampleRate, false);
audioSource.clip = audioClip;
}
if (audioSource.isPlaying == false)
{
audioSource.Play();
}
if (!once && isPlayAudio && stream is StreamCompositeWithAudio streamAudio)
{
once = true;
float ptsSec = 0;
int nSamples = 0;
while (streamAudio.GetAudioClipData(ref ptsSec) && ptsSec < 200) // JUST FOR TEST
{
float[] data = streamAudio.GetAudioData();
audioSource.clip.SetData(data, nSamples);
nSamples += data.Length;
}
}
}
Когда вызываю playSound() метод, то я слышу голос и слова, но есть 2 проблемы -
- Очень много шума, такое впечатление как будто слушаю старый приемник
- Речь затянута, как будто жевачку тянут.
Насчет первого пункта, я думал, что может проблема в количестве каналов, но нет - у меня один канал и соответсвенно 1 я передаю как параметр. Откуда берется этот шум? Как можно это подебажить, чтоб понять?
и насчет второго пункта: AudioClip.Create("AudioVoice", (int)(mAudioLengthSamples * justForTestNum * 1.2), (int)mAudioChannels, (int)(mAudioSampleRate), false); и тут mAudioSampleRate = 44100 если я умножаю этот параметр на 2 то эффект жевачки пропадает или audioSource.pitch = audioPitch; дефолтное значение 1, но если я передаю 2, то тоже эффект жевачки пропадает, но вопрос в том, почему мне нужно умножать это значение на 2? Если 44100 это мой стандартный сампл рейт?
Ответы (1 шт):
Речь затянута, как будто жевачку тянут.
mAudioSampleRate = 44100если я умножаю этот параметр на 2 то эффект жевачки пропадает.
Потому что у вас 16-битный звук, а вы его переводите как 8-битный звук. В итоге каждый второй (или первый, зависит от порядка байт) результирующий байт несет испорченную информацию. Общее время звуковой дорожки увеличивается в 2 раза, именно поэтому "умножение" сэмплрейта на 2 решает проблему. Был бы у вас 64-битный звук, сэмплрейт нужно было бы увеличивать в 4 раза.
Очень много шума, такое впечатление как будто слушаю старый приемник
Вы каждый байт [0..255] нормализуете значением 32767 и получаете очень "схожие" значения, например:
0 / 32767 = 0
255 / 32767 = 0.007 ~= 0
Либо у вас очень специфичная звуковая дорожка, либо вы что-то перепутали, Pitch должен сгладить эту ошибку перевода, но на "скорость" он никак не должен влиять.
Фрагмент, помеченный ??? endian - один из вариантов перевода, я не знаю, в каком порядке ваша библиотека записывает байты, меняйте местами leastSigByte с mostSigByte по своей ситуации.
private static float[] Convert16BitByteArrayToAudioClipData(byte[] source) {
float[] buffer = new float[source.Length / 2];
int normalizationValue = Int32.MaxValue;
for (int i = 0; i < buffer.Length; i++) {
// ??? endian
var sampleByteIndex = i * 2;
var leastSigByte = source[sampleByteIndex];
var mostSigByte = source[sampleByteIndex + 1] << 8;
// ??? endian
buffer[i] = (float)(mostSigByte + leastSigByte) / normalizationValue;
}
return buffer;
}