/* Copyright (C) 2003 Marcus Overhagen * Released under terms of the MIT license. * * A simple resampling class for the audio mixer. * You pick the conversation function on object creation, * and then call the Resample() function, specifying data pointer, * offset (in bytes) to the next sample, and count of samples for * both source and destination. * */ #include #include "Resampler.h" #include "debug.h" Resampler::Resampler(uint32 src_format, uint32 dst_format) : fFunc(0) { if (dst_format == media_raw_audio_format::B_AUDIO_FLOAT) { switch (src_format) { case media_raw_audio_format::B_AUDIO_FLOAT: fFunc = &Resampler::float_to_float; return; case media_raw_audio_format::B_AUDIO_INT: fFunc = &Resampler::int32_to_float; return; case media_raw_audio_format::B_AUDIO_SHORT: fFunc = &Resampler::int16_to_float; return; case media_raw_audio_format::B_AUDIO_CHAR: fFunc = &Resampler::int8_to_float; return; case media_raw_audio_format::B_AUDIO_UCHAR: fFunc = &Resampler::uint8_to_float; return; default: ERROR("Resampler::Resampler: unknown source format 0x%x\n", src_format); return; } } if (src_format == media_raw_audio_format::B_AUDIO_FLOAT) { switch (dst_format) { // float=>float already handled above case media_raw_audio_format::B_AUDIO_INT: fFunc = &Resampler::float_to_int32; return; case media_raw_audio_format::B_AUDIO_SHORT: fFunc = &Resampler::float_to_int16; return; case media_raw_audio_format::B_AUDIO_CHAR: fFunc = &Resampler::float_to_int8; return; case media_raw_audio_format::B_AUDIO_UCHAR: fFunc = &Resampler::float_to_uint8; return; default: ERROR("Resampler::Resampler: unknown destination format 0x%x\n", dst_format); return; } } ERROR("Resampler::Resampler: source or destination format must be B_AUDIO_FLOAT\n"); } Resampler::~Resampler() { } status_t Resampler::InitCheck() { return (fFunc != 0) ? B_OK : B_ERROR; } void Resampler::float_to_float(const void *_src, int32 src_sample_offset, int32 src_sample_count, void *_dst, int32 dst_sample_offset, int32 dst_sample_count, float _gain) { register const char * src = (const char *) _src; register char * dst = (char *) _dst; register int32 count = dst_sample_count; register float gain = _gain; if (src_sample_count == dst_sample_count) { // optimized case for no resampling while (count--) { *(float *)dst = *(const float *)src * gain; src += src_sample_offset; dst += dst_sample_offset; } return; } register float delta = float(src_sample_count) / float(dst_sample_count); register float current = 0.0f; if (delta < 1.0) { // upsample while (count--) { *(float *)dst = *(const float *)src * gain; dst += dst_sample_offset; current += delta; if (current >= 1.0f) { current -= 1.0f; src += src_sample_offset; } } } else { // downsample while (count--) { *(float *)dst = *(const float *)src * gain; dst += dst_sample_offset; current += delta; register int32 skipcount = (int32)current; current -= skipcount; src += skipcount * src_sample_offset; } } } void Resampler::int32_to_float(const void *_src, int32 src_sample_offset, int32 src_sample_count, void *_dst, int32 dst_sample_offset, int32 dst_sample_count, float _gain) { register const char * src = (const char *) _src; register char * dst = (char *) _dst; register int32 count = dst_sample_count; register float gain = _gain / 2147483647.0; if (src_sample_count == dst_sample_count) { // optimized case for no resampling while (count--) { *(float *)dst = *(const int32 *)src * gain; src += src_sample_offset; dst += dst_sample_offset; } return; } register float delta = float(src_sample_count) / float(dst_sample_count); register float current = 0.0f; if (delta < 1.0) { // upsample while (count--) { *(float *)dst = *(const int32 *)src * gain; dst += dst_sample_offset; current += delta; if (current >= 1.0f) { current -= 1.0f; src += src_sample_offset; } } } else { // downsample while (count--) { *(float *)dst = *(const int32 *)src * gain; dst += dst_sample_offset; current += delta; register int32 skipcount = (int32)current; current -= skipcount; src += skipcount * src_sample_offset; } } } void Resampler::int16_to_float(const void *_src, int32 src_sample_offset, int32 src_sample_count, void *_dst, int32 dst_sample_offset, int32 dst_sample_count, float _gain) { register const char * src = (const char *) _src; register char * dst = (char *) _dst; register int32 count = dst_sample_count; register float gain = _gain / 32767.0; if (src_sample_count == dst_sample_count) { // optimized case for no resampling while (count--) { *(float *)dst = *(const int16 *)src * gain; src += src_sample_offset; dst += dst_sample_offset; } return; } register float delta = float(src_sample_count) / float(dst_sample_count); register float current = 0.0f; if (delta < 1.0) { // upsample while (count--) { *(float *)dst = *(const int16 *)src * gain; dst += dst_sample_offset; current += delta; if (current >= 1.0f) { current -= 1.0f; src += src_sample_offset; } } } else { // downsample while (count--) { *(float *)dst = *(const int16 *)src * gain; dst += dst_sample_offset; current += delta; register int32 skipcount = (int32)current; current -= skipcount; src += skipcount * src_sample_offset; } } } void Resampler::int8_to_float(const void *_src, int32 src_sample_offset, int32 src_sample_count, void *_dst, int32 dst_sample_offset, int32 dst_sample_count, float _gain) { register const char * src = (const char *) _src; register char * dst = (char *) _dst; register int32 count = dst_sample_count; register float gain = _gain / 127.0; if (src_sample_count == dst_sample_count) { // optimized case for no resampling while (count--) { *(float *)dst = *(const int8 *)src * gain; src += src_sample_offset; dst += dst_sample_offset; } return; } register float delta = float(src_sample_count) / float(dst_sample_count); register float current = 0.0f; if (delta < 1.0) { // upsample while (count--) { *(float *)dst = *(const int8 *)src * gain; dst += dst_sample_offset; current += delta; if (current >= 1.0f) { current -= 1.0f; src += src_sample_offset; } } } else { // downsample while (count--) { *(float *)dst = *(const int8 *)src * gain; dst += dst_sample_offset; current += delta; register int32 skipcount = (int32)current; current -= skipcount; src += skipcount * src_sample_offset; } } } void Resampler::uint8_to_float(const void *_src, int32 src_sample_offset, int32 src_sample_count, void *_dst, int32 dst_sample_offset, int32 dst_sample_count, float _gain) { register const char * src = (const char *) _src; register char * dst = (char *) _dst; register int32 count = dst_sample_count; register float gain = _gain / 127.0; if (src_sample_count == dst_sample_count) { // optimized case for no resampling while (count--) { *(float *)dst = (((int32) *(const uint8 *)src) - 128) * gain; src += src_sample_offset; dst += dst_sample_offset; } return; } register float delta = float(src_sample_count) / float(dst_sample_count); register float current = 0.0f; if (delta < 1.0) { // upsample while (count--) { *(float *)dst = (((int32) *(const uint8 *)src) - 128) * gain; dst += dst_sample_offset; current += delta; if (current >= 1.0f) { current -= 1.0f; src += src_sample_offset; } } } else { // downsample while (count--) { *(float *)dst = (((int32) *(const uint8 *)src) - 128) * gain; dst += dst_sample_offset; current += delta; register int32 skipcount = (int32)current; current -= skipcount; src += skipcount * src_sample_offset; } } } void Resampler::float_to_int32(const void *_src, int32 src_sample_offset, int32 src_sample_count, void *_dst, int32 dst_sample_offset, int32 dst_sample_count, float _gain) { register const char * src = (const char *) _src; register char * dst = (char *) _dst; register int32 count = dst_sample_count; register float gain = _gain * 2147483647.0; if (src_sample_count == dst_sample_count) { // optimized case for no resampling while (count--) { register float sample = *(const float *)src * gain; if (sample > 2147483647.0f) *(int32 *)dst = 2147483647L; else if (sample < -2147483647.0f) *(int32 *)dst = -2147483647L; else *(int32 *)dst = (int32)sample; src += src_sample_offset; dst += dst_sample_offset; } return; } register float delta = float(src_sample_count) / float(dst_sample_count); register float current = 0.0f; if (delta < 1.0) { // upsample while (count--) { register float sample = *(const float *)src * gain; if (sample > 2147483647.0f) *(int32 *)dst = 2147483647L; else if (sample < -2147483647.0f) *(int32 *)dst = -2147483647L; else *(int32 *)dst = (int32)sample; dst += dst_sample_offset; current += delta; if (current >= 1.0f) { current -= 1.0f; src += src_sample_offset; } } } else { // downsample while (count--) { register float sample = *(const float *)src * gain; if (sample > 2147483647.0f) *(int32 *)dst = 2147483647L; else if (sample < -2147483647.0f) *(int32 *)dst = -2147483647L; else *(int32 *)dst = (int32)sample; dst += dst_sample_offset; current += delta; register int32 skipcount = (int32)current; current -= skipcount; src += skipcount * src_sample_offset; } } } void Resampler::float_to_int16(const void *_src, int32 src_sample_offset, int32 src_sample_count, void *_dst, int32 dst_sample_offset, int32 dst_sample_count, float _gain) { register const char * src = (const char *) _src; register char * dst = (char *) _dst; register int32 count = dst_sample_count; register float gain = _gain * 32767.0; if (src_sample_count == dst_sample_count) { // optimized case for no resampling while (count--) { register float sample = *(const float *)src * gain; if (sample > 32767.0f) *(int16 *)dst = 32767; else if (sample < -32767.0f) *(int16 *)dst = -32767; else *(int16 *)dst = (int16)sample; src += src_sample_offset; dst += dst_sample_offset; } return; } register float delta = float(src_sample_count) / float(dst_sample_count); register float current = 0.0f; if (delta < 1.0) { // upsample while (count--) { register float sample = *(const float *)src * gain; if (sample > 32767.0f) *(int16 *)dst = 32767; else if (sample < -32767.0f) *(int16 *)dst = -32767; else *(int16 *)dst = (int16)sample; dst += dst_sample_offset; current += delta; if (current >= 1.0f) { current -= 1.0f; src += src_sample_offset; } } } else { // downsample while (count--) { register float sample = *(const float *)src * gain; if (sample > 32767.0f) *(int16 *)dst = 32767; else if (sample < -32767.0f) *(int16 *)dst = -32767; else *(int16 *)dst = (int16)sample; dst += dst_sample_offset; current += delta; register int32 skipcount = (int32)current; current -= skipcount; src += skipcount * src_sample_offset; } } } void Resampler::float_to_int8(const void *_src, int32 src_sample_offset, int32 src_sample_count, void *_dst, int32 dst_sample_offset, int32 dst_sample_count, float _gain) { register const char * src = (const char *) _src; register char * dst = (char *) _dst; register int32 count = dst_sample_count; register float gain = _gain * 127.0; if (src_sample_count == dst_sample_count) { // optimized case for no resampling while (count--) { register float sample = *(const float *)src * gain; if (sample > 127.0f) *(int8 *)dst = 127; else if (sample < -127.0f) *(int8 *)dst = -127; else *(int8 *)dst = (int8)sample; src += src_sample_offset; dst += dst_sample_offset; } return; } register float delta = float(src_sample_count) / float(dst_sample_count); register float current = 0.0f; if (delta < 1.0) { // upsample while (count--) { register float sample = *(const float *)src * gain; if (sample > 127.0f) *(int8 *)dst = 127; else if (sample < -127.0f) *(int8 *)dst = -127; else *(int8 *)dst = (int8)sample; dst += dst_sample_offset; current += delta; if (current >= 1.0f) { current -= 1.0f; src += src_sample_offset; } } } else { // downsample while (count--) { register float sample = *(const float *)src * gain; if (sample > 127.0f) *(int8 *)dst = 127; else if (sample < -127.0f) *(int8 *)dst = -127; else *(int8 *)dst = (int8)sample; dst += dst_sample_offset; current += delta; register int32 skipcount = (int32)current; current -= skipcount; src += skipcount * src_sample_offset; } } } void Resampler::float_to_uint8(const void *_src, int32 src_sample_offset, int32 src_sample_count, void *_dst, int32 dst_sample_offset, int32 dst_sample_count, float _gain) { register const char * src = (const char *) _src; register char * dst = (char *) _dst; register int32 count = dst_sample_count; register float gain = _gain * 127.0; if (src_sample_count == dst_sample_count) { // optimized case for no resampling while (count--) { register float sample = 128.0f + *(const float *)src * gain; if (sample > 255.0f) *(uint8 *)dst = 255; else if (sample < 1.0f) *(uint8 *)dst = 1; else *(uint8 *)dst = (uint8)sample; src += src_sample_offset; dst += dst_sample_offset; } return; } register float delta = float(src_sample_count) / float(dst_sample_count); register float current = 0.0f; if (delta < 1.0) { // upsample while (count--) { register float sample = 128.0f + *(const float *)src * gain; if (sample > 255.0f) *(uint8 *)dst = 255; else if (sample < 1.0f) *(uint8 *)dst = 1; else *(uint8 *)dst = (uint8)sample; dst += dst_sample_offset; current += delta; if (current >= 1.0f) { current -= 1.0f; src += src_sample_offset; } } } else { // downsample while (count--) { register float sample = 128.0f + *(const float *)src * gain; if (sample > 255.0f) *(uint8 *)dst = 255; else if (sample < 1.0f) *(uint8 *)dst = 1; else *(uint8 *)dst = (uint8)sample; dst += dst_sample_offset; current += delta; register int32 skipcount = (int32)current; current -= skipcount; src += skipcount * src_sample_offset; } } }