Author: pulkomandy Date: 2010-08-12 12:18:38 +0200 (Thu, 12 Aug 2010) New Revision: 38037 Changeset: http://dev.haiku-os.org/changeset/38037 Added: haiku/trunk/src/add-ons/media/media-add-ons/mixer/Interpolate.cpp haiku/trunk/src/add-ons/media/media-add-ons/mixer/Interpolate.h Modified: haiku/trunk/src/add-ons/media/media-add-ons/mixer/Jamfile haiku/trunk/src/add-ons/media/media-add-ons/mixer/MixerCore.cpp haiku/trunk/src/add-ons/media/media-add-ons/mixer/MixerInput.cpp Log: * Add a resampler that interpolates instead of dropping/copying samples. * Not plugged anywhere yet. * I'm not sure the downsampling is done properly, either. Added: haiku/trunk/src/add-ons/media/media-add-ons/mixer/Interpolate.cpp =================================================================== --- haiku/trunk/src/add-ons/media/media-add-ons/mixer/Interpolate.cpp (rev 0) +++ haiku/trunk/src/add-ons/media/media-add-ons/mixer/Interpolate.cpp 2010-08-12 10:18:38 UTC (rev 38037) @@ -0,0 +1,559 @@ +/* + * Copyright 2010 Adrien Destugues <pulkomandy@xxxxxxxxxxxxxxxxx> + * 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; + } + } +} + Added: haiku/trunk/src/add-ons/media/media-add-ons/mixer/Interpolate.h =================================================================== --- haiku/trunk/src/add-ons/media/media-add-ons/mixer/Interpolate.h (rev 0) +++ haiku/trunk/src/add-ons/media/media-add-ons/mixer/Interpolate.h 2010-08-12 10:18:38 UTC (rev 38037) @@ -0,0 +1,58 @@ +/* + * Copyright 2010, Adrien Destugues <pulkomandy@xxxxxxxxxxxxxxxxx> + * 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 Modified: haiku/trunk/src/add-ons/media/media-add-ons/mixer/Jamfile =================================================================== --- haiku/trunk/src/add-ons/media/media-add-ons/mixer/Jamfile 2010-08-12 08:01:05 UTC (rev 38036) +++ haiku/trunk/src/add-ons/media/media-add-ons/mixer/Jamfile 2010-08-12 10:18:38 UTC (rev 38037) @@ -5,6 +5,7 @@ Addon mixer.media_addon : AudioMixer.cpp ByteSwap.cpp + Interpolate.cpp MixerAddOn.cpp MixerCore.cpp MixerInput.cpp Modified: haiku/trunk/src/add-ons/media/media-add-ons/mixer/MixerCore.cpp =================================================================== --- haiku/trunk/src/add-ons/media/media-add-ons/mixer/MixerCore.cpp 2010-08-12 08:01:05 UTC (rev 38036) +++ haiku/trunk/src/add-ons/media/media-add-ons/mixer/MixerCore.cpp 2010-08-12 10:18:38 UTC (rev 38037) @@ -296,6 +296,7 @@ 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); } Modified: haiku/trunk/src/add-ons/media/media-add-ons/mixer/MixerInput.cpp =================================================================== --- haiku/trunk/src/add-ons/media/media-add-ons/mixer/MixerInput.cpp 2010-08-12 08:01:05 UTC (rev 38036) +++ haiku/trunk/src/add-ons/media/media-add-ons/mixer/MixerInput.cpp 2010-08-12 10:18:38 UTC (rev 38037) @@ -76,6 +76,7 @@ // 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()