Преобразование 16-битного PCM в 8-битное

У меня есть звук PCM, хранящийся в массиве байтов. Это 16 бит на выборку. Я хочу сделать его 8-битным на образец аудио.

Может ли кто-нибудь предложить хороший алгоритм для этого?

Я не упомянул битрейт, потому что думаю, что он не важен для алгоритма, верно?


person gop    schedule 19.04.2011    source источник
comment
Битрейт может быть важен (но не обязательно) - например. при работе с аналого-цифровыми преобразователями (при работе со звуком вы, наконец, выводите его через АЦП), вы можете увеличить частоту дискретизации в 65 000 раз (если я правильно рассчитал), чтобы получить более высокое разрешение с меньшим количеством битов (это называется передискретизацией). ).   -  person flolo    schedule 19.04.2011
comment
Это не java, но посмотрите, как это реализует ffmpeg. Просмотрите код здесь: ffmpeg.org/doxygen/0.5/pcm_8c-source.html< /а>   -  person Aleadam    schedule 19.04.2011
comment
@gosho_ot_pochivka Не могли бы вы рассказать мне, как преобразовать 16-битный PCM в 24-битный. Спасибо   -  person ravi    schedule 24.02.2016


Ответы (4)


Я не понимаю прямо сейчас, почему недостаточно просто взять старший байт, то есть отбросить младшие 8 бит каждого образца.

Это, конечно, предполагает, что выборки линейны; если это не так, то, возможно, вам нужно что-то сделать, чтобы линеаризовать их, прежде чем отбрасывать биты.

short sixteenBit = 0xfeed;
byte eightBit = sixteenBit >> 8;
// eightBit is now 0xfe.

Как предложил AShelly в комментарии, может быть хорошей идеей округлить, т.е. добавить 1, если отбрасываемый байт больше половины своего максимума:

eightBit += eightBit < 0xff && ((sixteenBit & 0xff) > 0x80);

Тест против 0xff реализует зажим, поэтому мы не рискуем добавить 1 к 0xff и обернуть это до 0x00, что было бы плохо.

person unwind    schedule 19.04.2011
comment
Вы также можете округлить вместо усечения. Добавьте «восемь бит += (шестнадцать бит и 0x80)››7;» чтобы добавить 1, если младший байт больше половины своего диапазона. - person AShelly; 19.04.2011
comment
@AShelly: правда, это может быть хорошей идеей ... Однако ваш код заставит значения в диапазоне от 0xff00 до 0xffff переноситься на 0x00, что, вероятно, хуже, чем отсутствие округления вообще. Я отредактирую. - person unwind; 20.04.2011
comment
благодаря. Если мой ввод находится в массиве байтов (байт [] arr не короткий), означает ли это просто отбросить половину байтов, т.е. взять arr[0] , arr[2], arr[4] и т. д.? - person gop; 20.04.2011
comment
@gosho-ot-pochivka: Да, я так думаю. Меня немного беспокоят проблемы со знаком, если образцы представляют собой 16-битные числа со знаком, но поскольку бит знака будет сохранен, все должно быть в порядке. - person unwind; 27.04.2011

16-битные сэмплы обычно знаковые, а 8-битные обычно беззнаковые, поэтому самый простой ответ заключается в том, что вам нужно преобразовать 16-битные сэмплы из знаковых (16-битные сэмплы почти всегда хранятся в диапазоне от -32768 до +32767) до беззнакового, а затем взять старшие 8 бит результата. В C это может быть выражено как output = (unsigned char)((unsigned short)(input + 32768) >> 8). Это хорошее начало, и оно может быть достаточно хорошим для ваших нужд, но звучит не очень хорошо. Звучит грубо из-за "шума квантования".

Шум квантования — это разница между исходным входом и выходом вашего алгоритма. Независимо от того, что вы делаете, у вас будет шум, и шум будет в среднем «полбита». С этим ничего не поделаешь, но есть способы сделать шум менее заметным.

Основная проблема с шумом квантования заключается в том, что он имеет тенденцию формировать шаблоны. Если бы разница между входом и выходом была полностью случайной, все на самом деле звучало бы нормально, но вместо этого выходной сигнал постоянно был бы слишком высоким для определенной части сигнала и слишком низким для следующей части. Ваше ухо улавливает этот образец.

Чтобы получить результат, который звучит хорошо, вам нужно добавить дизеринг. Дизеринг — это метод, который пытается сгладить шум квантования. Самый простой дизеринг просто удаляет шаблоны из шума, чтобы шаблоны шума не отвлекали от реальных шаблонов сигнала. Лучшее сглаживание может пойти еще дальше и предпринять шаги для уменьшения шума путем сложения значений ошибок из нескольких выборок, а затем добавления коррекции, когда общая ошибка становится достаточно большой, чтобы ее можно было исправить.

Объяснения и примеры кода для различных алгоритмов сглаживания можно найти в Интернете. Одной из хороших областей для изучения может быть инструмент SoX, http://en.wikipedia.org/wiki/SoX< /а>. Проверьте источник на наличие эффекта сглаживания и поэкспериментируйте с преобразованием различных звуков из 16-битного в 8-битное с включенным сглаживанием и без него. Вы будете удивлены той разницей в качестве, которую может дать дизеринг при преобразовании в 8-битный звук.

person user2774867    schedule 13.09.2013

byteData = (byte) (((shortData +32768)>>8)& 0xFF) 

это сработало для меня.

person Akash Raghav    schedule 09.12.2015

Нормализуйте 16-битные образцы, затем измените масштаб на максимальное значение вашего 8-битного образца.

Это дает более точное преобразование, так как младшие 8 битов каждой выборки не отбрасываются. Однако мое решение требует больших вычислительных затрат, чем выбранный ответ.

person William Morrison    schedule 12.11.2012