don't overflow when we do digital amplification of 16 bit samples

This commit is contained in:
Lennart Poettering 2009-01-23 19:40:01 +01:00
parent ddbe6126d3
commit 2a238b2d7f

View file

@ -213,13 +213,22 @@ size_t pa_mix(
for (i = 0; i < nstreams; i++) { for (i = 0; i < nstreams; i++) {
pa_mix_info *m = streams + i; pa_mix_info *m = streams + i;
int32_t v, cv = m->linear[channel].i; int32_t v, lo, hi, cv = m->linear[channel].i;
if (PA_UNLIKELY(cv <= 0)) if (PA_UNLIKELY(cv <= 0))
continue; continue;
/* Multiplying the 32bit volume factor with the
* 16bit sample might result in an 48bit value. We
* want to do without 64 bit integers and hence do
* the multiplication independantly for the HI and
* LO part of the volume. */
hi = cv >> 16;
lo = cv & 0xFFFF;
v = *((int16_t*) m->ptr); v = *((int16_t*) m->ptr);
v = (v * cv) / 0x10000; v = ((v * lo) >> 16) + (v * hi);
sum += v; sum += v;
m->ptr = (uint8_t*) m->ptr + sizeof(int16_t); m->ptr = (uint8_t*) m->ptr + sizeof(int16_t);
@ -248,13 +257,16 @@ size_t pa_mix(
for (i = 0; i < nstreams; i++) { for (i = 0; i < nstreams; i++) {
pa_mix_info *m = streams + i; pa_mix_info *m = streams + i;
int32_t v, cv = m->linear[channel].i; int32_t v, lo, hi, cv = m->linear[channel].i;
if (PA_UNLIKELY(cv <= 0)) if (PA_UNLIKELY(cv <= 0))
continue; continue;
hi = cv >> 16;
lo = cv & 0xFFFF;
v = PA_INT16_SWAP(*((int16_t*) m->ptr)); v = PA_INT16_SWAP(*((int16_t*) m->ptr));
v = (v * cv) / 0x10000; v = ((v * lo) >> 16) + (v * hi);
sum += v; sum += v;
m->ptr = (uint8_t*) m->ptr + sizeof(int16_t); m->ptr = (uint8_t*) m->ptr + sizeof(int16_t);
@ -290,7 +302,7 @@ size_t pa_mix(
continue; continue;
v = *((int32_t*) m->ptr); v = *((int32_t*) m->ptr);
v = (v * cv) / 0x10000; v = (v * cv) >> 16;
sum += v; sum += v;
m->ptr = (uint8_t*) m->ptr + sizeof(int32_t); m->ptr = (uint8_t*) m->ptr + sizeof(int32_t);
@ -326,7 +338,7 @@ size_t pa_mix(
continue; continue;
v = PA_INT32_SWAP(*((int32_t*) m->ptr)); v = PA_INT32_SWAP(*((int32_t*) m->ptr));
v = (v * cv) / 0x10000; v = (v * cv) >> 16;
sum += v; sum += v;
m->ptr = (uint8_t*) m->ptr + sizeof(int32_t); m->ptr = (uint8_t*) m->ptr + sizeof(int32_t);
@ -362,7 +374,7 @@ size_t pa_mix(
continue; continue;
v = (int32_t) (PA_READ24NE(m->ptr) << 8); v = (int32_t) (PA_READ24NE(m->ptr) << 8);
v = (v * cv) / 0x10000; v = (v * cv) >> 16;
sum += v; sum += v;
m->ptr = (uint8_t*) m->ptr + 3; m->ptr = (uint8_t*) m->ptr + 3;
@ -398,7 +410,7 @@ size_t pa_mix(
continue; continue;
v = (int32_t) (PA_READ24RE(m->ptr) << 8); v = (int32_t) (PA_READ24RE(m->ptr) << 8);
v = (v * cv) / 0x10000; v = (v * cv) >> 16;
sum += v; sum += v;
m->ptr = (uint8_t*) m->ptr + 3; m->ptr = (uint8_t*) m->ptr + 3;
@ -434,7 +446,7 @@ size_t pa_mix(
continue; continue;
v = (int32_t) (*((uint32_t*)m->ptr) << 8); v = (int32_t) (*((uint32_t*)m->ptr) << 8);
v = (v * cv) / 0x10000; v = (v * cv) >> 16;
sum += v; sum += v;
m->ptr = (uint8_t*) m->ptr + sizeof(int32_t); m->ptr = (uint8_t*) m->ptr + sizeof(int32_t);
@ -470,7 +482,7 @@ size_t pa_mix(
continue; continue;
v = (int32_t) (PA_UINT32_SWAP(*((uint32_t*) m->ptr)) << 8); v = (int32_t) (PA_UINT32_SWAP(*((uint32_t*) m->ptr)) << 8);
v = (v * cv) / 0x10000; v = (v * cv) >> 16;
sum += v; sum += v;
m->ptr = (uint8_t*) m->ptr + 3; m->ptr = (uint8_t*) m->ptr + 3;
@ -505,7 +517,7 @@ size_t pa_mix(
continue; continue;
v = (int32_t) *((uint8_t*) m->ptr) - 0x80; v = (int32_t) *((uint8_t*) m->ptr) - 0x80;
v = (v * cv) / 0x10000; v = (v * cv) >> 16;
sum += v; sum += v;
m->ptr = (uint8_t*) m->ptr + 1; m->ptr = (uint8_t*) m->ptr + 1;
@ -534,13 +546,16 @@ size_t pa_mix(
for (i = 0; i < nstreams; i++) { for (i = 0; i < nstreams; i++) {
pa_mix_info *m = streams + i; pa_mix_info *m = streams + i;
int32_t v, cv = m->linear[channel].i; int32_t v, hi, lo, cv = m->linear[channel].i;
if (PA_UNLIKELY(cv <= 0)) if (PA_UNLIKELY(cv <= 0))
continue; continue;
hi = cv >> 16;
lo = cv & 0xFFFF;
v = (int32_t) st_ulaw2linear16(*((uint8_t*) m->ptr)); v = (int32_t) st_ulaw2linear16(*((uint8_t*) m->ptr));
v = (v * cv) / 0x10000; v = ((v * lo) >> 16) + (v * hi);
sum += v; sum += v;
m->ptr = (uint8_t*) m->ptr + 1; m->ptr = (uint8_t*) m->ptr + 1;
@ -569,13 +584,16 @@ size_t pa_mix(
for (i = 0; i < nstreams; i++) { for (i = 0; i < nstreams; i++) {
pa_mix_info *m = streams + i; pa_mix_info *m = streams + i;
int32_t v, cv = m->linear[channel].i; int32_t v, hi, lo, cv = m->linear[channel].i;
if (PA_UNLIKELY(cv <= 0)) if (PA_UNLIKELY(cv <= 0))
continue; continue;
hi = cv >> 16;
lo = cv & 0xFFFF;
v = (int32_t) st_alaw2linear16(*((uint8_t*) m->ptr)); v = (int32_t) st_alaw2linear16(*((uint8_t*) m->ptr));
v = (v * cv) / 0x10000; v = ((v * lo) >> 16) + (v * hi);
sum += v; sum += v;
m->ptr = (uint8_t*) m->ptr + 1; m->ptr = (uint8_t*) m->ptr + 1;
@ -710,16 +728,26 @@ void pa_volume_memchunk(
e = (int16_t*) ptr + c->length/sizeof(int16_t); e = (int16_t*) ptr + c->length/sizeof(int16_t);
for (channel = 0, d = ptr; d < e; d++) { for (channel = 0, d = ptr; d < e; d++) {
int32_t t; int32_t t, hi, lo;
/* Multiplying the 32bit volume factor with the 16bit
* sample might result in an 48bit value. We want to
* do without 64 bit integers and hence do the
* multiplication independantly for the HI and LO part
* of the volume. */
hi = linear[channel] >> 16;
lo = linear[channel] & 0xFFFF;
t = (int32_t)(*d); t = (int32_t)(*d);
t = (t * linear[channel]) / 0x10000; t = ((t * lo) >> 16) + (t * hi);
t = PA_CLAMP_UNLIKELY(t, -0x8000, 0x7FFF); t = PA_CLAMP_UNLIKELY(t, -0x8000, 0x7FFF);
*d = (int16_t) t; *d = (int16_t) t;
if (PA_UNLIKELY(++channel >= spec->channels)) if (PA_UNLIKELY(++channel >= spec->channels))
channel = 0; channel = 0;
} }
break; break;
} }
@ -733,10 +761,13 @@ void pa_volume_memchunk(
e = (int16_t*) ptr + c->length/sizeof(int16_t); e = (int16_t*) ptr + c->length/sizeof(int16_t);
for (channel = 0, d = ptr; d < e; d++) { for (channel = 0, d = ptr; d < e; d++) {
int32_t t; int32_t t, hi, lo;
hi = linear[channel] >> 16;
lo = linear[channel] & 0xFFFF;
t = (int32_t) PA_INT16_SWAP(*d); t = (int32_t) PA_INT16_SWAP(*d);
t = (t * linear[channel]) / 0x10000; t = ((t * lo) >> 16) + (t * hi);
t = PA_CLAMP_UNLIKELY(t, -0x8000, 0x7FFF); t = PA_CLAMP_UNLIKELY(t, -0x8000, 0x7FFF);
*d = PA_INT16_SWAP((int16_t) t); *d = PA_INT16_SWAP((int16_t) t);
@ -760,7 +791,7 @@ void pa_volume_memchunk(
int64_t t; int64_t t;
t = (int64_t)(*d); t = (int64_t)(*d);
t = (t * linear[channel]) / 0x10000; t = (t * linear[channel]) >> 16;
t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL); t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL);
*d = (int32_t) t; *d = (int32_t) t;
@ -783,7 +814,7 @@ void pa_volume_memchunk(
int64_t t; int64_t t;
t = (int64_t) PA_INT32_SWAP(*d); t = (int64_t) PA_INT32_SWAP(*d);
t = (t * linear[channel]) / 0x10000; t = (t * linear[channel]) >> 16;
t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL); t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL);
*d = PA_INT32_SWAP((int32_t) t); *d = PA_INT32_SWAP((int32_t) t);
@ -806,7 +837,7 @@ void pa_volume_memchunk(
int64_t t; int64_t t;
t = (int64_t)((int32_t) (PA_READ24NE(d) << 8)); t = (int64_t)((int32_t) (PA_READ24NE(d) << 8));
t = (t * linear[channel]) / 0x10000; t = (t * linear[channel]) >> 16;
t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL); t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL);
PA_WRITE24NE(d, ((uint32_t) (int32_t) t) >> 8); PA_WRITE24NE(d, ((uint32_t) (int32_t) t) >> 8);
@ -829,7 +860,7 @@ void pa_volume_memchunk(
int64_t t; int64_t t;
t = (int64_t)((int32_t) (PA_READ24RE(d) << 8)); t = (int64_t)((int32_t) (PA_READ24RE(d) << 8));
t = (t * linear[channel]) / 0x10000; t = (t * linear[channel]) >> 16;
t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL); t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL);
PA_WRITE24RE(d, ((uint32_t) (int32_t) t) >> 8); PA_WRITE24RE(d, ((uint32_t) (int32_t) t) >> 8);
@ -852,7 +883,7 @@ void pa_volume_memchunk(
int64_t t; int64_t t;
t = (int64_t) ((int32_t) (*d << 8)); t = (int64_t) ((int32_t) (*d << 8));
t = (t * linear[channel]) / 0x10000; t = (t * linear[channel]) >> 16;
t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL); t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL);
*d = ((uint32_t) ((int32_t) t)) >> 8; *d = ((uint32_t) ((int32_t) t)) >> 8;
@ -875,7 +906,7 @@ void pa_volume_memchunk(
int64_t t; int64_t t;
t = (int64_t) ((int32_t) (PA_UINT32_SWAP(*d) << 8)); t = (int64_t) ((int32_t) (PA_UINT32_SWAP(*d) << 8));
t = (t * linear[channel]) / 0x10000; t = (t * linear[channel]) >> 16;
t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL); t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL);
*d = PA_UINT32_SWAP(((uint32_t) ((int32_t) t)) >> 8); *d = PA_UINT32_SWAP(((uint32_t) ((int32_t) t)) >> 8);
@ -895,10 +926,13 @@ void pa_volume_memchunk(
e = (uint8_t*) ptr + c->length; e = (uint8_t*) ptr + c->length;
for (channel = 0, d = ptr; d < e; d++) { for (channel = 0, d = ptr; d < e; d++) {
int32_t t; int32_t t, hi, lo;
hi = linear[channel] >> 16;
lo = linear[channel] & 0xFFFF;
t = (int32_t) *d - 0x80; t = (int32_t) *d - 0x80;
t = (t * linear[channel]) / 0x10000; t = ((t * lo) >> 16) + (t * hi);
t = PA_CLAMP_UNLIKELY(t, -0x80, 0x7F); t = PA_CLAMP_UNLIKELY(t, -0x80, 0x7F);
*d = (uint8_t) (t + 0x80); *d = (uint8_t) (t + 0x80);
@ -918,10 +952,13 @@ void pa_volume_memchunk(
e = (uint8_t*) ptr + c->length; e = (uint8_t*) ptr + c->length;
for (channel = 0, d = ptr; d < e; d++) { for (channel = 0, d = ptr; d < e; d++) {
int32_t t; int32_t t, hi, lo;
hi = linear[channel] >> 16;
lo = linear[channel] & 0xFFFF;
t = (int32_t) st_ulaw2linear16(*d); t = (int32_t) st_ulaw2linear16(*d);
t = (t * linear[channel]) / 0x10000; t = ((t * lo) >> 16) + (t * hi);
t = PA_CLAMP_UNLIKELY(t, -0x8000, 0x7FFF); t = PA_CLAMP_UNLIKELY(t, -0x8000, 0x7FFF);
*d = (uint8_t) st_14linear2ulaw((int16_t) t >> 2); *d = (uint8_t) st_14linear2ulaw((int16_t) t >> 2);
@ -941,10 +978,13 @@ void pa_volume_memchunk(
e = (uint8_t*) ptr + c->length; e = (uint8_t*) ptr + c->length;
for (channel = 0, d = ptr; d < e; d++) { for (channel = 0, d = ptr; d < e; d++) {
int32_t t; int32_t t, hi, lo;
hi = linear[channel] >> 16;
lo = linear[channel] & 0xFFFF;
t = (int32_t) st_alaw2linear16(*d); t = (int32_t) st_alaw2linear16(*d);
t = (t * linear[channel]) / 0x10000; t = ((t * lo) >> 16) + (t * hi);
t = PA_CLAMP_UNLIKELY(t, -0x8000, 0x7FFF); t = PA_CLAMP_UNLIKELY(t, -0x8000, 0x7FFF);
*d = (uint8_t) st_13linear2alaw((int16_t) t >> 3); *d = (uint8_t) st_13linear2alaw((int16_t) t >> 3);