From ff617a11dda81e55fd32cfc1a6e926d14c4fbe9e Mon Sep 17 00:00:00 2001 From: Adrien Destugues Date: Thu, 12 Aug 2010 10:18:38 +0000 Subject: [PATCH] * 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 --- .../media/media-add-ons/mixer/Interpolate.cpp | 559 ++++++++++++++++++ .../media/media-add-ons/mixer/Interpolate.h | 58 ++ src/add-ons/media/media-add-ons/mixer/Jamfile | 1 + .../media/media-add-ons/mixer/MixerCore.cpp | 1 + .../media/media-add-ons/mixer/MixerInput.cpp | 1 + 5 files changed, 620 insertions(+) create mode 100644 src/add-ons/media/media-add-ons/mixer/Interpolate.cpp create mode 100644 src/add-ons/media/media-add-ons/mixer/Interpolate.h diff --git a/src/add-ons/media/media-add-ons/mixer/Interpolate.cpp b/src/add-ons/media/media-add-ons/mixer/Interpolate.cpp new file mode 100644 index 0000000000..efa0f5fff3 --- /dev/null +++ b/src/add-ons/media/media-add-ons/mixer/Interpolate.cpp @@ -0,0 +1,559 @@ +/* + * Copyright 2010 Adrien Destugues + * Distributed under the terms of the MIT Licence. + */ + + +#include "Interpolate.h" + +#include + + +/*! 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; + } + } +} + diff --git a/src/add-ons/media/media-add-ons/mixer/Interpolate.h b/src/add-ons/media/media-add-ons/mixer/Interpolate.h new file mode 100644 index 0000000000..0ddaf0cd3c --- /dev/null +++ b/src/add-ons/media/media-add-ons/mixer/Interpolate.h @@ -0,0 +1,58 @@ +/* + * Copyright 2010, Adrien Destugues + * 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 diff --git a/src/add-ons/media/media-add-ons/mixer/Jamfile b/src/add-ons/media/media-add-ons/mixer/Jamfile index 6f2a8be6f5..64134e4f79 100644 --- a/src/add-ons/media/media-add-ons/mixer/Jamfile +++ b/src/add-ons/media/media-add-ons/mixer/Jamfile @@ -5,6 +5,7 @@ SetSubDirSupportedPlatformsBeOSCompatible ; Addon mixer.media_addon : AudioMixer.cpp ByteSwap.cpp + Interpolate.cpp MixerAddOn.cpp MixerCore.cpp MixerInput.cpp diff --git a/src/add-ons/media/media-add-ons/mixer/MixerCore.cpp b/src/add-ons/media/media-add-ons/mixer/MixerCore.cpp index b86fcc05bb..4e33593d69 100644 --- a/src/add-ons/media/media-add-ons/mixer/MixerCore.cpp +++ b/src/add-ons/media/media-add-ons/mixer/MixerCore.cpp @@ -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); } diff --git a/src/add-ons/media/media-add-ons/mixer/MixerInput.cpp b/src/add-ons/media/media-add-ons/mixer/MixerInput.cpp index 3eae420196..3ae6cd656e 100644 --- a/src/add-ons/media/media-add-ons/mixer/MixerInput.cpp +++ b/src/add-ons/media/media-add-ons/mixer/MixerInput.cpp @@ -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()