summaryrefslogtreecommitdiffstats
path: root/src/pulsecore/sample-util.c
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2009-01-23 19:40:01 +0100
committerLennart Poettering <lennart@poettering.net>2009-01-23 19:40:01 +0100
commit2a238b2d7f000dfd2c7b0db82f557951f93f3809 (patch)
tree0a10c35c99f4076418959cb3b3f7578835960823 /src/pulsecore/sample-util.c
parentddbe6126d365a77ed94aee0b961d7cd334ea2a9b (diff)
don't overflow when we do digital amplification of 16 bit samples
Diffstat (limited to 'src/pulsecore/sample-util.c')
-rw-r--r--src/pulsecore/sample-util.c102
1 files changed, 71 insertions, 31 deletions
diff --git a/src/pulsecore/sample-util.c b/src/pulsecore/sample-util.c
index cf7b4d58..905ba5df 100644
--- a/src/pulsecore/sample-util.c
+++ b/src/pulsecore/sample-util.c
@@ -213,13 +213,22 @@ size_t pa_mix(
for (i = 0; i < nstreams; 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))
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 = (v * cv) / 0x10000;
+ v = ((v * lo) >> 16) + (v * hi);
sum += v;
m->ptr = (uint8_t*) m->ptr + sizeof(int16_t);
@@ -248,13 +257,16 @@ size_t pa_mix(
for (i = 0; i < nstreams; 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))
continue;
+ hi = cv >> 16;
+ lo = cv & 0xFFFF;
+
v = PA_INT16_SWAP(*((int16_t*) m->ptr));
- v = (v * cv) / 0x10000;
+ v = ((v * lo) >> 16) + (v * hi);
sum += v;
m->ptr = (uint8_t*) m->ptr + sizeof(int16_t);
@@ -290,7 +302,7 @@ size_t pa_mix(
continue;
v = *((int32_t*) m->ptr);
- v = (v * cv) / 0x10000;
+ v = (v * cv) >> 16;
sum += v;
m->ptr = (uint8_t*) m->ptr + sizeof(int32_t);
@@ -326,7 +338,7 @@ size_t pa_mix(
continue;
v = PA_INT32_SWAP(*((int32_t*) m->ptr));
- v = (v * cv) / 0x10000;
+ v = (v * cv) >> 16;
sum += v;
m->ptr = (uint8_t*) m->ptr + sizeof(int32_t);
@@ -362,7 +374,7 @@ size_t pa_mix(
continue;
v = (int32_t) (PA_READ24NE(m->ptr) << 8);
- v = (v * cv) / 0x10000;
+ v = (v * cv) >> 16;
sum += v;
m->ptr = (uint8_t*) m->ptr + 3;
@@ -398,7 +410,7 @@ size_t pa_mix(
continue;
v = (int32_t) (PA_READ24RE(m->ptr) << 8);
- v = (v * cv) / 0x10000;
+ v = (v * cv) >> 16;
sum += v;
m->ptr = (uint8_t*) m->ptr + 3;
@@ -434,7 +446,7 @@ size_t pa_mix(
continue;
v = (int32_t) (*((uint32_t*)m->ptr) << 8);
- v = (v * cv) / 0x10000;
+ v = (v * cv) >> 16;
sum += v;
m->ptr = (uint8_t*) m->ptr + sizeof(int32_t);
@@ -470,7 +482,7 @@ size_t pa_mix(
continue;
v = (int32_t) (PA_UINT32_SWAP(*((uint32_t*) m->ptr)) << 8);
- v = (v * cv) / 0x10000;
+ v = (v * cv) >> 16;
sum += v;
m->ptr = (uint8_t*) m->ptr + 3;
@@ -505,7 +517,7 @@ size_t pa_mix(
continue;
v = (int32_t) *((uint8_t*) m->ptr) - 0x80;
- v = (v * cv) / 0x10000;
+ v = (v * cv) >> 16;
sum += v;
m->ptr = (uint8_t*) m->ptr + 1;
@@ -534,13 +546,16 @@ size_t pa_mix(
for (i = 0; i < nstreams; 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))
continue;
+ hi = cv >> 16;
+ lo = cv & 0xFFFF;
+
v = (int32_t) st_ulaw2linear16(*((uint8_t*) m->ptr));
- v = (v * cv) / 0x10000;
+ v = ((v * lo) >> 16) + (v * hi);
sum += v;
m->ptr = (uint8_t*) m->ptr + 1;
@@ -569,13 +584,16 @@ size_t pa_mix(
for (i = 0; i < nstreams; 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))
continue;
+ hi = cv >> 16;
+ lo = cv & 0xFFFF;
+
v = (int32_t) st_alaw2linear16(*((uint8_t*) m->ptr));
- v = (v * cv) / 0x10000;
+ v = ((v * lo) >> 16) + (v * hi);
sum += v;
m->ptr = (uint8_t*) m->ptr + 1;
@@ -710,16 +728,26 @@ void pa_volume_memchunk(
e = (int16_t*) ptr + c->length/sizeof(int16_t);
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 = (t * linear[channel]) / 0x10000;
+ t = ((t * lo) >> 16) + (t * hi);
t = PA_CLAMP_UNLIKELY(t, -0x8000, 0x7FFF);
*d = (int16_t) t;
if (PA_UNLIKELY(++channel >= spec->channels))
channel = 0;
}
+
break;
}
@@ -733,10 +761,13 @@ void pa_volume_memchunk(
e = (int16_t*) ptr + c->length/sizeof(int16_t);
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 = (t * linear[channel]) / 0x10000;
+ t = ((t * lo) >> 16) + (t * hi);
t = PA_CLAMP_UNLIKELY(t, -0x8000, 0x7FFF);
*d = PA_INT16_SWAP((int16_t) t);
@@ -760,7 +791,7 @@ void pa_volume_memchunk(
int64_t t;
t = (int64_t)(*d);
- t = (t * linear[channel]) / 0x10000;
+ t = (t * linear[channel]) >> 16;
t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL);
*d = (int32_t) t;
@@ -783,7 +814,7 @@ void pa_volume_memchunk(
int64_t t;
t = (int64_t) PA_INT32_SWAP(*d);
- t = (t * linear[channel]) / 0x10000;
+ t = (t * linear[channel]) >> 16;
t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL);
*d = PA_INT32_SWAP((int32_t) t);
@@ -806,7 +837,7 @@ void pa_volume_memchunk(
int64_t t;
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);
PA_WRITE24NE(d, ((uint32_t) (int32_t) t) >> 8);
@@ -829,7 +860,7 @@ void pa_volume_memchunk(
int64_t t;
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);
PA_WRITE24RE(d, ((uint32_t) (int32_t) t) >> 8);
@@ -852,7 +883,7 @@ void pa_volume_memchunk(
int64_t t;
t = (int64_t) ((int32_t) (*d << 8));
- t = (t * linear[channel]) / 0x10000;
+ t = (t * linear[channel]) >> 16;
t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL);
*d = ((uint32_t) ((int32_t) t)) >> 8;
@@ -875,7 +906,7 @@ void pa_volume_memchunk(
int64_t t;
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);
*d = PA_UINT32_SWAP(((uint32_t) ((int32_t) t)) >> 8);
@@ -895,10 +926,13 @@ void pa_volume_memchunk(
e = (uint8_t*) ptr + c->length;
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 = (t * linear[channel]) / 0x10000;
+ t = ((t * lo) >> 16) + (t * hi);
t = PA_CLAMP_UNLIKELY(t, -0x80, 0x7F);
*d = (uint8_t) (t + 0x80);
@@ -918,10 +952,13 @@ void pa_volume_memchunk(
e = (uint8_t*) ptr + c->length;
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 = (t * linear[channel]) / 0x10000;
+ t = ((t * lo) >> 16) + (t * hi);
t = PA_CLAMP_UNLIKELY(t, -0x8000, 0x7FFF);
*d = (uint8_t) st_14linear2ulaw((int16_t) t >> 2);
@@ -941,10 +978,13 @@ void pa_volume_memchunk(
e = (uint8_t*) ptr + c->length;
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 = (t * linear[channel]) / 0x10000;
+ t = ((t * lo) >> 16) + (t * hi);
t = PA_CLAMP_UNLIKELY(t, -0x8000, 0x7FFF);
*d = (uint8_t) st_13linear2alaw((int16_t) t >> 3);