OpenGTA/util/sound_resample2.cpp
Anonymous Maarten e20673c2cd 2007-04-16
2015-12-03 01:37:37 +01:00

93 lines
3.7 KiB
C++

/************************************************************************
* Copyright (c) 2005-2007 tok@openlinux.org.uk *
* *
* This software is provided as-is, without any express or implied *
* warranty. In no event will the authors be held liable for any *
* damages arising from the use of this software. *
* *
* Permission is granted to anyone to use this software for any purpose, *
* including commercial applications, and to alter it and redistribute *
* it freely, subject to the following restrictions: *
* *
* 1. The origin of this software must not be misrepresented; you must *
* not claim that you wrote the original software. If you use this *
* software in a product, an acknowledgment in the product documentation *
* would be appreciated but is not required. *
* *
* 2. Altered source versions must be plainly marked as such, and must *
* not be misrepresented as being the original software. *
* *
* 3. This notice may not be removed or altered from any source *
* distribution. *
************************************************************************/
#include "sound_resample2.h"
#include "interpolate.hpp"
namespace Audio {
// resample uint8 mono to Sint16 stereo
// assumption: src_rate < wanted_rate
// derived from some sweet code found in the exult repository,
// now rewritten to avoid license trouble...
// yes, it is (still) similiar - who would have guessed?
Sint16 *resample_new (Uint8 * src, size_t sourcelen, size_t & size,
int rate, int wanted_rate) {
int fp_pos = 0;
int fp_speed = (1 << 16) * rate / wanted_rate;
size = sourcelen;
// adjust the magnitudes of size and rate to prevent division error
while (size & 0xFFFF0000)
size >>= 1, rate = (rate >> 1) + 1;
// Compute the output size (times 4 since it is 16 stereo)
size = (size * wanted_rate / rate) << 2;
Sint16 *stereo_data = new Sint16[size];
Sint16 *data = stereo_data;
Uint8 *src_end = src + sourcelen;
int result;
// Compute the initial data feed for the interpolator. We don't simply
// shift by 8, but rather duplicate the byte, this way we cover the full
// range. Probably doesn't make a big difference, listening wise :-)
int a = *(src + 0);
a = (a | (a << 8)) - 32768;
int b = *(src + 1);
b = (a | (b << 8)) - 32768;
int c = *(src + 2);
c = (a | (c << 8)) - 32768;
// scale down by 0.8333 to avoid oversampling
Math::Interpolator::Cubic<float> inter(a * 0.8333f, b * 0.8333f, c * 0.8333f);
do
{
do
{
result = int(inter.getAt(fp_pos / float(0x0000FFFF)));
// limit the range
if (result < -32768)
result = -32768;
else if (result > 32767)
result = 32767;
*data++ = result;
*data++ = result;
fp_pos += fp_speed;
}
while (!(fp_pos & 0xFFFF0000)); // need more input data
src++;
fp_pos &= 0x0000FFFF;
if (src + 2 < src_end) // still data to fetch
{
c = *(src + 2);
c = (c | (c << 8)) - 32768;
inter.shiftAndFeed (c * 0.8333f);
}
else // guess & interpolate... this the end, my only friend the end
inter.shift ();
}
while (src < src_end);
return stereo_data;
}
}