fix bugs in interpolating resampler :

* I got the downsampling version completely wrong. It should now be much better.
 * A small bug in the delta calculation sometimes caused an off-by-one read to the source and a crash of the media add-on server

Effect of this resampler can be heard very clearly using the following setup in Cortex :
 * Demo Audio producer producing a sinewave at any frequency (sampling rate is hardcoded at 44100Hz)
 * Audio output set to 48000 Hz
 * system mixer in between
select either resampler in the mixer and you'll hear the difference immediately.

Should finally fix #1351.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@42435 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Adrien Destugues 2011-07-16 09:15:21 +00:00
parent 4ee20b83b4
commit 61215fd53d
1 changed files with 109 additions and 250 deletions

View File

@ -44,32 +44,19 @@ Interpolate::float_to_float(const void *_src, int32 srcSampleOffset,
return;
}
register float delta = float(srcSampleCount) / float(destSampleCount);
register float delta = float(srcSampleCount - 1) / float(destSampleCount - 1);
register float current = 0.0f;
#define SRC(n) *(const float*)(src + n * srcSampleOffset)
if (delta < 1.0) {
// upsample
while (count--) {
*(float*)dest = gain * (SRC(0) + (SRC(1) - SRC(0)) * current) ;
dest += destSampleOffset;
current += delta;
if (current >= 1.0f) {
current -= 1.0f;
src += srcSampleOffset;
}
}
} else {
// downsample
while (count--) {
double skipcount;
register float offset = modf(current, &skipcount);
*(float*)dest = gain
* (SRC(0) + (SRC((int)skipcount) - SRC(0)) * offset);
dest += destSampleOffset;
current += delta - skipcount;
src += (int)skipcount * srcSampleOffset;
double ipart;
current = modf(current, &ipart);
src += srcSampleOffset * (int)ipart;
}
}
}
@ -95,33 +82,20 @@ Interpolate::int32_to_float(const void *_src, int32 srcSampleOffset,
return;
}
register float delta = float(srcSampleCount) / float(destSampleCount);
register float delta = float(srcSampleCount - 1) / float(destSampleCount - 1);
register float current = 0.0f;
#undef SRC
#define SRC(n) *(const int32*)(src + n * srcSampleOffset)
if (delta < 1.0) {
// upsample
while (count--) {
*(float*)dest = gain * (SRC(0) + (SRC(1) - SRC(0)) * current) ;
dest += destSampleOffset;
current += delta;
if (current >= 1.0f) {
current -= 1.0f;
src += srcSampleOffset;
}
}
} else {
// downsample
while (count--) {
double skipcount;
register float offset = modf(current, &skipcount);
*(float*)dest = gain * (SRC(0) + (SRC((int)skipcount) - SRC(0))
* offset);
dest += destSampleOffset;
current += delta - skipcount;
src += (int)skipcount * srcSampleOffset;
double ipart;
current = modf(current, &ipart);
src += srcSampleOffset * (int)ipart;
}
}
}
@ -147,33 +121,20 @@ Interpolate::int16_to_float(const void *_src, int32 srcSampleOffset,
return;
}
register float delta = float(srcSampleCount) / float(destSampleCount);
register float delta = float(srcSampleCount - 1) / float(destSampleCount - 1);
register float current = 0.0f;
#undef SRC
#define SRC(n) *(const int16*)(src + n * srcSampleOffset)
if (delta < 1.0) {
// upsample
while (count--) {
*(float*)dest = gain * (SRC(0) + (SRC(1) - SRC(0)) * current);
dest += destSampleOffset;
current += delta;
if (current >= 1.0f) {
current -= 1.0f;
src += srcSampleOffset;
}
}
} else {
// downsample
while (count--) {
double skipcount;
register float offset = modf(current, &skipcount);
*(float*)dest = gain * (SRC(0) + (SRC((int)skipcount) - SRC(0))
* offset);
dest += destSampleOffset;
current += delta - skipcount;
src += (int)skipcount * srcSampleOffset;
double ipart;
current = modf(current, &ipart);
src += srcSampleOffset * (int)ipart;
}
}
}
@ -199,33 +160,20 @@ Interpolate::int8_to_float(const void *_src, int32 srcSampleOffset,
return;
}
register float delta = float(srcSampleCount) / float(destSampleCount);
register float delta = float(srcSampleCount - 1) / float(destSampleCount - 1);
register float current = 0.0f;
#undef SRC
#define SRC(n) *(const int8*)(src + n * srcSampleOffset)
if (delta < 1.0) {
// upsample
while (count--) {
*(float*)dest = gain * (SRC(0) + (SRC(1) - SRC(0)) * current) ;
dest += destSampleOffset;
current += delta;
if (current >= 1.0f) {
current -= 1.0f;
src += srcSampleOffset;
}
}
} else {
// downsample
while (count--) {
double skipcount;
register float offset = modf(current, &skipcount);
*(float*)dest = gain * (SRC(0) + (SRC((int)skipcount) - SRC(0))
* offset);
dest += destSampleOffset;
current += delta - skipcount;
src += (int)skipcount * srcSampleOffset;
double ipart;
current = modf(current, &ipart);
src += srcSampleOffset * (int)ipart;
}
}
}
@ -251,33 +199,20 @@ Interpolate::uint8_to_float(const void *_src, int32 srcSampleOffset,
return;
}
register float delta = float(srcSampleCount) / float(destSampleCount);
register float delta = float(srcSampleCount - 1) / float(destSampleCount - 1);
register float current = 0.0f;
#undef SRC
#define SRC(n) ( *(const uint8*)(src + n * srcSampleOffset) - 128)
if (delta < 1.0) {
// upsample
while (count--) {
*(float*)dest = gain * (SRC(0) + (SRC(1) - SRC(0)) * current);
dest += destSampleOffset;
current += delta;
if (current >= 1.0f) {
current -= 1.0f;
src += srcSampleOffset;
}
}
} else {
// downsample
while (count--) {
double skipcount;
register float offset = modf(current, &skipcount);
*(float*)dest = gain * (SRC(0) + (SRC((int)skipcount) - SRC(0))
* offset);
dest += destSampleOffset;
current += delta - skipcount;
src += (int)skipcount * srcSampleOffset;
double ipart;
current = modf(current, &ipart);
src += srcSampleOffset * (int)ipart;
}
}
}
@ -309,14 +244,12 @@ Interpolate::float_to_int32(const void *_src, int32 srcSampleOffset,
return;
}
register float delta = float(srcSampleCount) / float(destSampleCount);
register float delta = float(srcSampleCount - 1) / float(destSampleCount - 1);
register float current = 0.0f;
#undef SRC
#define SRC(n) *(const float*)(src + n * srcSampleOffset)
if (delta < 1.0) {
// upsample
while (count--) {
register float sample = gain * (SRC(0) + (SRC(1) - SRC(0))
* current);
@ -329,26 +262,9 @@ Interpolate::float_to_int32(const void *_src, int32 srcSampleOffset,
dest += destSampleOffset;
current += delta;
if (current >= 1.0f) {
current -= 1.0f;
src += srcSampleOffset;
}
}
} else {
// downsample
while (count--) {
double skipcount;
register float offset = modf(current, &skipcount);
register float sample = gain * (SRC(0) + (SRC((int)skipcount)
- SRC(0)) * offset);
if (sample > 2147483647.0f)
*(int32 *)dest = 2147483647L;
else if (sample < -2147483647.0f)
*(int32 *)dest = -2147483647L;
else
*(int32 *)dest = (int32)sample;
dest += destSampleOffset;
current += delta - skipcount;
src += (int)skipcount * srcSampleOffset;
double ipart;
current = modf(current, &ipart);
src += srcSampleOffset * (int)ipart;
}
}
}
@ -380,11 +296,9 @@ Interpolate::float_to_int16(const void *_src, int32 srcSampleOffset,
return;
}
register float delta = float(srcSampleCount) / float(destSampleCount);
register float delta = float(srcSampleCount - 1) / float(destSampleCount - 1);
register float current = 0.0f;
if (delta < 1.0) {
// upsample
while (count--) {
register float sample = gain * (SRC(0) + (SRC(1) - SRC(0))
* current);
@ -397,26 +311,9 @@ Interpolate::float_to_int16(const void *_src, int32 srcSampleOffset,
dest += destSampleOffset;
current += delta;
if (current >= 1.0f) {
current -= 1.0f;
src += srcSampleOffset;
}
}
} else {
// downsample
while (count--) {
double skipcount;
register float offset = modf(current, &skipcount);
register float sample = gain * (SRC(0) + (SRC((int)skipcount)
- SRC(0)) * offset);
if (sample > 32767.0f)
*(int16 *)dest = 32767;
else if (sample < -32767.0f)
*(int16 *)dest = -32767;
else
*(int16 *)dest = (int16)sample;
dest += destSampleOffset;
current += delta - skipcount;
src += (int)skipcount * srcSampleOffset;
double ipart;
current = modf(current, &ipart);
src += srcSampleOffset * (int)ipart;
}
}
}
@ -448,11 +345,9 @@ Interpolate::float_to_int8(const void *_src, int32 srcSampleOffset,
return;
}
register float delta = float(srcSampleCount) / float(destSampleCount);
register float delta = float(srcSampleCount - 1) / float(destSampleCount - 1);
register float current = 0.0f;
if (delta < 1.0) {
// upsample
while (count--) {
register float sample = gain * (SRC(0) + (SRC(1) - SRC(0))
* current);
@ -465,26 +360,9 @@ Interpolate::float_to_int8(const void *_src, int32 srcSampleOffset,
dest += destSampleOffset;
current += delta;
if (current >= 1.0f) {
current -= 1.0f;
src += srcSampleOffset;
}
}
} else {
// downsample
while (count--) {
double skipcount;
register float offset = modf(current, &skipcount);
register float sample = gain * (SRC(0) + (SRC((int)skipcount)
- SRC(0)) * offset);
if (sample > 127.0f)
*(int8 *)dest = 127;
else if (sample < -127.0f)
*(int8 *)dest = -127;
else
*(int8 *)dest = (int8)sample;
dest += destSampleOffset;
current += delta - skipcount;
src += (int)skipcount * srcSampleOffset;
double ipart;
current = modf(current, &ipart);
src += srcSampleOffset * (int)ipart;
}
}
}
@ -516,11 +394,9 @@ Interpolate::float_to_uint8(const void *_src, int32 srcSampleOffset,
return;
}
register float delta = float(srcSampleCount) / float(destSampleCount);
register float delta = float(srcSampleCount - 1) / float(destSampleCount - 1);
register float current = 0.0f;
if (delta < 1.0) {
// upsample
while (count--) {
register float sample = gain * (SRC(0) + (SRC(1) - SRC(0))
* current);
@ -533,26 +409,9 @@ Interpolate::float_to_uint8(const void *_src, int32 srcSampleOffset,
dest += destSampleOffset;
current += delta;
if (current >= 1.0f) {
current -= 1.0f;
src += srcSampleOffset;
}
}
} else {
// downsample
while (count--) {
double skipcount;
register float offset = modf(current, &skipcount);
register float sample = gain * (SRC(0) + (SRC((int)skipcount)
- SRC(0)) * offset) + 128.0f;
if (sample > 255.0f)
*(uint8 *)dest = 255;
else if (sample < 1.0f)
*(uint8 *)dest = 1;
else
*(uint8 *)dest = (uint8)sample;
dest += destSampleOffset;
current += delta - skipcount;
src += (int)skipcount * srcSampleOffset;
double ipart;
current = modf(current, &ipart);
src += srcSampleOffset * (int)ipart;
}
}
}