Я пытаюсь нормализовать звуковой файл речи.
В частности, если аудиофайл содержит пики в объеме, я пытаюсь его выровнять, поэтому тихие разделы громче, а пики более тихие.
Я очень мало знаю об обработке аудио, помимо того, что я узнал от работы над этой задачей. Кроме того, моя математика неловко слаба.
Я провел некоторое исследование, и сайт Xuggle предоставляет образец, который показывает уменьшение объема, используя следующий код: (полная версия здесь)
@Override
public void onAudioSamples(IAudioSamplesEvent event)
{
// get the raw audio byes and adjust it value
ShortBuffer buffer = event.getAudioSamples().getByteBuffer().asShortBuffer();
for (int i = 0; i < buffer.limit(); ++i)
buffer.put(i, (short)(buffer.get(i) * mVolume));
super.onAudioSamples(event);
}
Здесь они изменяют байты в getAudioSamples()
константой mVolume
.
Основываясь на этом подходе, я попытался нормализовать байты в getAudioSamples()
до нормализованного значения, считая max/min в файле. (Подробнее см. Ниже). У меня есть простой фильтр, чтобы оставить "тишину" в одиночку (т.е. Что-нибудь ниже значения).
Я нахожу, что выходной файл очень шумный (т.е. качество серьезно ухудшается). Я предполагаю, что ошибка либо в моем алгоритме нормализации, либо в том, как я манипулирую байтами. Однако я не уверен, куда идти дальше.
Здесь сокращенная версия того, что я сейчас делаю.
Шаг 1: Найти пики в файле:
Считывает полный аудиофайл и находит это самое высокое и самое низкое значение buffer.get()
для всех AudioSamples
@Override
public void onAudioSamples(IAudioSamplesEvent event) {
IAudioSamples audioSamples = event.getAudioSamples();
ShortBuffer buffer =
audioSamples.getByteBuffer().asShortBuffer();
short min = Short.MAX_VALUE;
short max = Short.MIN_VALUE;
for (int i = 0; i < buffer.limit(); ++i) {
short value = buffer.get(i);
min = (short) Math.min(min, value);
max = (short) Math.max(max, value);
}
// assign of min/max ommitted for brevity.
super.onAudioSamples(event);
}
Шаг 2: Нормализовать все значения:
В цикле, аналогичном шагу 1, замените буфер на нормализованные значения, вызвав:
buffer.put(i, normalize(buffer.get(i));
public short normalize(short value) {
if (isBackgroundNoise(value))
return value;
short rawMin = // min from step1
short rawMax = // max from step1
short targetRangeMin = 1000;
short targetRangeMax = 8000;
int abs = Math.abs(value);
double a = (abs - rawMin) * (targetRangeMax - targetRangeMin);
double b = (rawMax - rawMin);
double result = targetRangeMin + ( a/b );
// Copy the sign of value to result.
result = Math.copySign(result,value);
return (short) result;
}
Вопросы:
- Является ли это допустимым подходом к попытке нормализовать аудиофайл?
- Является ли моя математика в
normalize()
действительной? - Почему это может привести к тому, что файл станет шумным, где подобный подход в демо-коде не работает?