* Add a resampler that interpolates instead of dropping/copying samples.

* Not plugged anywhere yet.
 * I'm not sure the downsampling is done properly, either.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@38037 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Adrien Destugues 2010-08-12 10:18:38 +00:00
parent 5c4b63b505
commit ff617a11dd
5 changed files with 620 additions and 0 deletions

View File

@ -0,0 +1,559 @@
/*
* Copyright 2010 Adrien Destugues <pulkomandy@pulkomandy.ath.cx>
* Distributed under the terms of the MIT Licence.
*/
#include "Interpolate.h"
#include <cmath>
/*! Resampling class doing linear interpolation.
*/
Interpolate::Interpolate(uint32 src_format, uint32 dst_format)
:
Resampler(src_format, dst_format)
{
}
Interpolate::~Interpolate()
{
}
void
Interpolate::float_to_float(const void *_src, int32 srcSampleOffset,
int32 srcSampleCount, void *_dest, int32 destSampleOffset,
int32 destSampleCount, float _gain)
{
register const char * src = (const char *)_src;
register char * dest = (char *)_dest;
register int32 count = destSampleCount;
register float gain = _gain;
if (srcSampleCount == destSampleCount) {
// optimized case for no resampling
while (count--) {
*(float *)dest = *(const float *)src * gain;
src += srcSampleOffset;
dest += destSampleOffset;
}
return;
}
register float delta = float(srcSampleCount) / float(destSampleCount);
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--) {
register 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;
}
}
}
void
Interpolate::int32_to_float(const void *_src, int32 srcSampleOffset,
int32 srcSampleCount, void *_dest, int32 destSampleOffset,
int32 destSampleCount, float _gain)
{
register const char * src = (const char *)_src;
register char * dest = (char *)_dest;
register int32 count = destSampleCount;
register float gain = _gain / 2147483647.0;
if (srcSampleCount == destSampleCount) {
// optimized case for no resampling
while (count--) {
*(float *)dest = *(const int32 *)src * gain;
src += srcSampleOffset;
dest += destSampleOffset;
}
return;
}
register float delta = float(srcSampleCount) / float(destSampleCount);
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--) {
register 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;
}
}
}
void
Interpolate::int16_to_float(const void *_src, int32 srcSampleOffset,
int32 srcSampleCount, void *_dest, int32 destSampleOffset,
int32 destSampleCount, float _gain)
{
register const char * src = (const char *)_src;
register char * dest = (char *)_dest;
register int32 count = destSampleCount;
register float gain = _gain / 32767.0;
if (srcSampleCount == destSampleCount) {
// optimized case for no resampling
while (count--) {
*(float *)dest = *(const int16 *)src * gain;
src += srcSampleOffset;
dest += destSampleOffset;
}
return;
}
register float delta = float(srcSampleCount) / float(destSampleCount);
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--) {
register 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;
}
}
}
void
Interpolate::int8_to_float(const void *_src, int32 srcSampleOffset,
int32 srcSampleCount, void *_dest, int32 destSampleOffset,
int32 destSampleCount, float _gain)
{
register const char * src = (const char *)_src;
register char * dest = (char *)_dest;
register int32 count = destSampleCount;
register float gain = _gain / 127.0;
if (srcSampleCount == destSampleCount) {
// optimized case for no resampling
while (count--) {
*(float *)dest = *(const int8 *)src * gain;
src += srcSampleOffset;
dest += destSampleOffset;
}
return;
}
register float delta = float(srcSampleCount) / float(destSampleCount);
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--) {
register 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;
}
}
}
void
Interpolate::uint8_to_float(const void *_src, int32 srcSampleOffset,
int32 srcSampleCount, void *_dest, int32 destSampleOffset,
int32 destSampleCount, float _gain)
{
register const char * src = (const char *)_src;
register char * dest = (char *)_dest;
register int32 count = destSampleCount;
register float gain = _gain / 127.0;
if (srcSampleCount == destSampleCount) {
// optimized case for no resampling
while (count--) {
*(float *)dest = (((int32) *(const uint8 *)src) - 128) * gain;
src += srcSampleOffset;
dest += destSampleOffset;
}
return;
}
register float delta = float(srcSampleCount) / float(destSampleCount);
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--) {
register 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;
}
}
}
void
Interpolate::float_to_int32(const void *_src, int32 srcSampleOffset,
int32 srcSampleCount, void *_dest, int32 destSampleOffset,
int32 destSampleCount, float _gain)
{
register const char * src = (const char *)_src;
register char * dest = (char *)_dest;
register int32 count = destSampleCount;
register float gain = _gain * 2147483647.0;
if (srcSampleCount == destSampleCount) {
// optimized case for no resampling
while (count--) {
register float sample = *(const float *)src * gain;
if (sample > 2147483647.0f)
*(int32 *)dest = 2147483647L;
else if (sample < -2147483647.0f)
*(int32 *)dest = -2147483647L;
else
*(int32 *)dest = (int32)sample;
src += srcSampleOffset;
dest += destSampleOffset;
}
return;
}
register float delta = float(srcSampleCount) / float(destSampleCount);
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);
if (sample > 2147483647.0f)
*(int32 *)dest = 2147483647L;
else if (sample < -2147483647.0f)
*(int32 *)dest = -2147483647L;
else
*(int32 *)dest = (int32)sample;
dest += destSampleOffset;
current += delta;
if (current >= 1.0f) {
current -= 1.0f;
src += srcSampleOffset;
}
}
} else {
// downsample
while (count--) {
register 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;
}
}
}
void
Interpolate::float_to_int16(const void *_src, int32 srcSampleOffset,
int32 srcSampleCount, void *_dest, int32 destSampleOffset,
int32 destSampleCount, float _gain)
{
register const char * src = (const char *)_src;
register char * dest = (char *)_dest;
register int32 count = destSampleCount;
register float gain = _gain * 32767.0;
if (srcSampleCount == destSampleCount) {
// optimized case for no resampling
while (count--) {
register float sample = *(const float *)src * gain;
if (sample > 32767.0f)
*(int16 *)dest = 32767;
else if (sample < -32767.0f)
*(int16 *)dest = -32767;
else
*(int16 *)dest = (int16)sample;
src += srcSampleOffset;
dest += destSampleOffset;
}
return;
}
register float delta = float(srcSampleCount) / float(destSampleCount);
register float current = 0.0f;
if (delta < 1.0) {
// upsample
while (count--) {
register float sample = gain * (SRC(0) + (SRC(1) - SRC(0))
* current);
if (sample > 32767.0f)
*(int16 *)dest = 32767;
else if (sample < -32767.0f)
*(int16 *)dest = -32767;
else
*(int16 *)dest = (int16)sample;
dest += destSampleOffset;
current += delta;
if (current >= 1.0f) {
current -= 1.0f;
src += srcSampleOffset;
}
}
} else {
// downsample
while (count--) {
register 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;
}
}
}
void
Interpolate::float_to_int8(const void *_src, int32 srcSampleOffset,
int32 srcSampleCount, void *_dest, int32 destSampleOffset,
int32 destSampleCount, float _gain)
{
register const char * src = (const char *)_src;
register char * dest = (char *)_dest;
register int32 count = destSampleCount;
register float gain = _gain * 127.0;
if (srcSampleCount == destSampleCount) {
// optimized case for no resampling
while (count--) {
register float sample = *(const float *)src * gain;
if (sample > 127.0f)
*(int8 *)dest = 127;
else if (sample < -127.0f)
*(int8 *)dest = -127;
else
*(int8 *)dest = (int8)sample;
src += srcSampleOffset;
dest += destSampleOffset;
}
return;
}
register float delta = float(srcSampleCount) / float(destSampleCount);
register float current = 0.0f;
if (delta < 1.0) {
// upsample
while (count--) {
register float sample = gain * (SRC(0) + (SRC(1) - SRC(0))
* current);
if (sample > 127.0f)
*(int8 *)dest = 127;
else if (sample < -127.0f)
*(int8 *)dest = -127;
else
*(int8 *)dest = (int8)sample;
dest += destSampleOffset;
current += delta;
if (current >= 1.0f) {
current -= 1.0f;
src += srcSampleOffset;
}
}
} else {
// downsample
while (count--) {
register 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;
}
}
}
void
Interpolate::float_to_uint8(const void *_src, int32 srcSampleOffset,
int32 srcSampleCount, void *_dest, int32 destSampleOffset,
int32 destSampleCount, float _gain)
{
register const char * src = (const char *)_src;
register char * dest = (char *)_dest;
register int32 count = destSampleCount;
register float gain = _gain * 127.0;
if (srcSampleCount == destSampleCount) {
// optimized case for no resampling
while (count--) {
register float sample = 128.0f + *(const float *)src * gain;
if (sample > 255.0f)
*(uint8 *)dest = 255;
else if (sample < 1.0f)
*(uint8 *)dest = 1;
else
*(uint8 *)dest = (uint8)sample;
src += srcSampleOffset;
dest += destSampleOffset;
}
return;
}
register float delta = float(srcSampleCount) / float(destSampleCount);
register float current = 0.0f;
if (delta < 1.0) {
// upsample
while (count--) {
register float sample = gain * (SRC(0) + (SRC(1) - SRC(0))
* current);
if (sample > 255.0f)
*(uint8 *)dest = 255;
else if (sample < 1.0f)
*(uint8 *)dest = 1;
else
*(uint8 *)dest = (uint8)sample;
dest += destSampleOffset;
current += delta;
if (current >= 1.0f) {
current -= 1.0f;
src += srcSampleOffset;
}
}
} else {
// downsample
while (count--) {
register 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;
}
}
}

View File

@ -0,0 +1,58 @@
/*
* Copyright 2010, Adrien Destugues <pulkomandy@pulkomandy.ath.cx>
* Distributed under the terms of the MIT Licence.
*/
#ifndef _INTERPOLATE_H
#define _INTERPOLATE_H
#include "Resampler.h"
class Interpolate: public Resampler {
public:
Interpolate(uint32 sourceFormat,
uint32 destFormat);
virtual ~Interpolate();
private:
virtual void float_to_float(const void* src,
int32 srcSampleOffset, int32 srcSampleCount,
void* dest, int32 destSampleOffset,
int32 destSampleCount, float gain);
virtual void int32_to_float(const void* src,
int32 srcSampleOffset, int32 srcSampleCount,
void* dest, int32 destSampleOffset,
int32 destSampleCount, float gain);
virtual void int16_to_float(const void* src,
int32 srcSampleOffset, int32 srcSampleCount,
void* dest, int32 destSampleOffset,
int32 destSampleCount, float gain);
virtual void int8_to_float(const void* src,
int32 srcSampleOffset, int32 srcSampleCount,
void* dest, int32 destSampleOffset,
int32 destSampleCount, float gain);
virtual void uint8_to_float(const void* src,
int32 srcSampleOffset, int32 srcSampleCount,
void* dest, int32 destSampleOffset,
int32 destSampleCount, float gain);
virtual void float_to_int32(const void* src,
int32 srcSampleOffset, int32 srcSampleCount,
void* dest, int32 destSampleOffset,
int32 destSampleCount, float gain);
virtual void float_to_int16(const void* src,
int32 srcSampleOffset, int32 srcSampleCount,
void* dest, int32 destSampleOffset,
int32 destSampleCount, float gain);
virtual void float_to_int8(const void* src,
int32 srcSampleOffset, int32 srcSampleCount,
void* dest, int32 destSampleOffset,
int32 destSampleCount, float gain);
virtual void float_to_uint8(const void* src,
int32 srcSampleOffset, int32 srcSampleCount,
void* dest, int32 destSampleOffset,
int32 destSampleCount, float gain);
};
#endif

View File

@ -5,6 +5,7 @@ SetSubDirSupportedPlatformsBeOSCompatible ;
Addon mixer.media_addon :
AudioMixer.cpp
ByteSwap.cpp
Interpolate.cpp
MixerAddOn.cpp
MixerCore.cpp
MixerInput.cpp

View File

@ -296,6 +296,7 @@ MixerCore::ApplyOutputFormat()
fResampler = new Resampler * [fMixBufferChannelCount];
for (int i = 0; i < fMixBufferChannelCount; i++) {
// TODO create Interpolate instead of Resampler if the settings say so
fResampler[i] = new Resampler(media_raw_audio_format::B_AUDIO_FLOAT,
format.format);
}

View File

@ -76,6 +76,7 @@ MixerInput::MixerInput(MixerCore *core, const media_input &input,
// create resamplers
fResampler = new Resampler * [fInputChannelCount];
for (int i = 0; i < fInputChannelCount; i++)
// TODO create Interpolate instead of Resampler if the settings says so
fResampler[i] = new Resampler(fInput.format.u.raw_audio.format, media_raw_audio_format::B_AUDIO_FLOAT);
// fMixerChannelInfo and fMixerChannelCount will be initialized by UpdateInputChannelDestinations()