开发者

pcm16 to pcm14 conversion using add + shift

I am studying a sound converting algorithm where an array of signed shorts is received.

At a given point in the algorithm it converts the samples from 16 bits to 14 bits, and it does it like this:

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

For me its clear that the shifting is needed as we want to get rid of the least 2 significant bits, but what about the 开发者_StackOverflow+2 there?


Shifting down loses the least significant two bits. If you just shift, then that will always round down, even if the bottom two bits are both set. Adding the 2 rounds up if the bigger of the bits being lost is set.

(Also worth noting that a better method of reducing the number of bits is to use dithering, i.e. adding a random (and very small) amount of noise before the reduction in sample size; this avoids the problem that, since the sounds are periodic, the rounding can often end up going consistently up or consistently down for a particular frequency, resulting in perceptible distortion in the sound. The wikipedia article linked explains it better than I can!)


I guess its intended to have the effect of rounding? I just hope that they conisdered the case of old_sample being more than MAX_INT16 - 2. Otherwise there might be issues when it overflows.


As others have noted, the +2 is an attempt to make the right shift perform a round-to-nearest division. However, there are two problems:

  • input samples of 32766 or 32767 may overflow int when 2 is added (int is only guaranteed to be able to represent numbers up to 32767);

  • The behaviour of a right shift of a negative number is implementation-defined.

To avoid these issues, it should be:

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

(Unlike the shift operator, the division operator in C99 is defined to round-towards-zero).


The intent of that code is probably rounding as is indicated in the other replies. But this is certainly a very bad example of it. There are two things going on here that the original programmer probably didn't intend:

  • promotion to int and re-assignment to int16_t
  • right shift of a signed value

Promotion to int (because of the +2 which is just an int) is bad here because you don't know what the precision of int on any random platform is that you happen to land on.

Right shift of signed values is compiler dependent if the value is negative, so the outcome may vary from platform to platform, too.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜