Преобразование из pcm16 в pcm14 с использованием add + shift - PullRequest
0 голосов
/ 06 июля 2010

Я изучаю алгоритм преобразования звука, при котором получается массив подписанных шорт.
В данный момент в алгоритме он преобразует выборки из 16 бит в 14 бит и делает это так:

int16_t sample = (old_sample + 2) >> 2;

Для меня ясно, что сдвиг необходим, поскольку мы хотим избавиться от 2 младших значащих битов, но как насчет +2 там?

Ответы [ 4 ]

8 голосов
/ 06 июля 2010

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

(Также стоит отметить, что лучший способ уменьшения количества битов - использовать дизеринг , то есть добавлениеслучайное (и очень небольшое) количество шума перед уменьшением размера выборки, что позволяет избежать проблемы, заключающейся в том, что, поскольку звуки являются периодическими, округление может часто заканчиваться последовательным повышением или последовательным снижением для определенной частоты, что приводит к заметному искажениюзвук. Связанная статья в википедии объясняет это лучше, чем я!)

1 голос
/ 07 июля 2010

Как уже отмечали другие, +2 - это попытка заставить правый сдвиг выполнить округление до ближайшего деления.Однако есть две проблемы:

  • входные выборки 32766 или 32767 могут переполниться int при добавлении 2 (int гарантированно сможет представлять числа до 32767);

  • Поведение правого сдвига отрицательного числа определяется реализацией.

Чтобы избежать этих проблем, должно быть:

int16_t sample = (old_sample > 0 ? old_sample + 2L : old_sample - 2L) / 4;

(В отличие от оператора сдвига, оператор деления в C99 определяется как округление к нулю).

1 голос
/ 06 июля 2010

Я предполагаю, что это должно иметь эффект округления?Я просто надеюсь, что они согласились с тем, что old_sample превышает MAX_INT16 - 2.В противном случае могут возникнуть проблемы при переполнении.

0 голосов
/ 06 июля 2010

Цель этого кода, вероятно, округляется, как указано в других ответах.Но это, безусловно, очень плохой пример.Здесь происходит две вещи, которые, вероятно, первоначальный программист не намеревался:

  • повышение до int и переназначение на int16_t
  • смещение вправо signed значение

Повышение до int (из-за +2, что является просто int) здесь плохо, потому что вы не знаете, какая точность int на любомслучайная платформа заключается в том, что вы попадаете на.

Сдвиг вправо signed значений зависит от компилятора, если значение отрицательное, поэтому результат может отличаться от платформы к платформе.

...