Fix wrap for AUDIO_INT

Floats don't have enough precision for all 32 bit integers. In
particular, near INT32_MAX their value is INT32_MAX + 1, which, when
converted back to int becomes INT32_MIN.

Change-Id: Ief3c1177b4f69baac13df5bac977882fea95ae01
Reviewed-on: https://review.haiku-os.org/c/haiku/+/3511
Reviewed-by: Adrien Destugues <pulkomandy@gmail.com>
This commit is contained in:
Máximo Castañeda 2020-12-11 20:43:11 +01:00 committed by Adrien Destugues
parent 4c8cf0257e
commit 2e68fbd207
7 changed files with 67 additions and 35 deletions

View File

@ -34,9 +34,12 @@ kernel(Resampler* object, const void *_src, int32 srcSampleOffset,
// optimized case for no resampling
while (count--) {
float tmp = ((*(const inType*)src) - inMiddle) * gain + outMiddle;
if (tmp < min) tmp = min;
if (tmp > max) tmp = max;
*(outType *)dest = (outType)tmp;
if (tmp <= min)
*(outType *)dest = min;
else if (tmp >= max)
*(outType *)dest = max;
else
*(outType *)dest = (outType)tmp;
src += srcSampleOffset;
dest += destSampleOffset;
}
@ -51,10 +54,13 @@ kernel(Resampler* object, const void *_src, int32 srcSampleOffset,
while (count--) {
float tmp = (gain * (oldSample + (SRC - oldSample) * current - inMiddle)
+ outMiddle);
if (tmp < min) tmp = min;
if (tmp > max) tmp = max;
*(outType *)dest = (outType)tmp;
+ outMiddle);
if (tmp <= min)
*(outType *)dest = min;
else if (tmp >= max)
*(outType *)dest = max;
else
*(outType *)dest = (outType)tmp;
dest += destSampleOffset;
current += delta;

View File

@ -34,9 +34,12 @@ kernel(Resampler* object, const void *_src, int32 srcSampleOffset,
// optimized case for no resampling
while (count--) {
float tmp = ((*(const inType*)src) - inMiddle) * gain + outMiddle;
if (tmp < min) tmp = min;
if (tmp > max) tmp = max;
*(outType *)dest = (outType)tmp;
if (tmp <= min)
*(outType *)dest = min;
else if (tmp >= max)
*(outType *)dest = max;
else
*(outType *)dest = (outType)tmp;
src += srcSampleOffset;
dest += destSampleOffset;
}
@ -49,9 +52,12 @@ kernel(Resampler* object, const void *_src, int32 srcSampleOffset,
// downsample
while (count--) {
float tmp = ((*(const inType*)src) - inMiddle) * gain + outMiddle;
if (tmp < min) tmp = min;
if (tmp > max) tmp = max;
*(outType *)dest = (outType)tmp;
if (tmp <= min)
*(outType *)dest = min;
else if (tmp >= max)
*(outType *)dest = max;
else
*(outType *)dest = (outType)tmp;
dest += destSampleOffset;
current += delta;

View File

@ -215,7 +215,13 @@ Resampler::_CopyFloat2Int(const void *inputData, uint32 inputStride,
void *outputData, uint32 outputStride, uint32 sampleCount)
{
while (sampleCount > 0) {
*(int32*)outputData = (int32)(*(const float*)inputData * 2147483647.0f);
float data = *(const float*)inputData;
if (data <= -1.0f)
*(int32*)outputData = INT32_MIN;
else if (data >= 1.0f)
*(int32*)outputData = INT32_MAX;
else
*(int32*)outputData = (int32)(data * INT32_MAX);
outputData = (void*)((uint8*)outputData + outputStride);
inputData = (void*)((uint8*)inputData + inputStride);
@ -304,7 +310,8 @@ Resampler::_CopyDouble2Int(const void *inputData, uint32 inputStride,
void *outputData, uint32 outputStride, uint32 sampleCount)
{
while (sampleCount > 0) {
*(int32*)outputData = (int32)(*(const double*)inputData * 2147483647.0f);
*(int32*)outputData = (int32)(*(const double*)inputData
* (double)INT32_MAX);
outputData = (void*)((uint8*)outputData + outputStride);
inputData = (void*)((uint8*)inputData + inputStride);

View File

@ -106,7 +106,7 @@ public:
inline operator uint8() const { int32 v = (int32)(data * 127.0f) + 128; if (v > 255) v = 255; else if (v < 0) v = 0; return v; }
inline operator int8() const { int32 v = (int32)(data * 127.0f); if (v > 127) v = 127; else if (v < -127) v = -127; return v; }
inline operator int16() const { int32 v = (int32)(data * 32767.0f); if (v > 32767) v = 32767; else if (v < -32767) v = -32767; return v; }
inline operator int32() const { float32 v; if (data < -1.0f) v = -1.0f; else if (data > 1.0f) v = 1.0f; else v = data; return (int32)(v * 2147483647.0f); }
inline operator int32() const { if (data <= -1.0f) return INT32_MIN; if (data >= 1.0f) return INT32_MAX; return (int32)(data * INT32_MAX); }
inline operator float() const { return data; }
private:
float32 data;
@ -118,7 +118,7 @@ public:
inline operator uint8() const { int32 v = (int32)(data * 127.0f) + 128; if (v > 255) v = 255; else if (v < 0) v = 0; return v; }
inline operator int8() const { int32 v = (int32)(data * 127.0f); if (v > 127) v = 127; else if (v < -127) v = -127; return v; }
inline operator int16() const { int32 v = (int32)(data * 32767.0f); if (v > 32767) v = 32767; else if (v < -32767) v = -32767; return v; }
inline operator int32() const { float64 v; if (data < -1.0) v = -1.0; else if (data > 1.0) v = 1.0; else v = data; return (int32)(v * 2147483647.0f); }
inline operator int32() const { float64 v; if (data < -1.0) v = -1.0; else if (data > 1.0) v = 1.0; else v = data; return (int32)(v * INT32_MAX); }
inline operator float() const { return data; }
private:
float64 data;

View File

@ -32,7 +32,7 @@ struct _gs_media_tracker {
// Local utility functions -----------------------------------------------
template<typename T, int middle>
template<typename T, int32 min, int32 middle, int32 max>
bool
FillBuffer(_gs_ramp* ramp, T* dest, const T* src, size_t* bytes)
{
@ -40,7 +40,8 @@ FillBuffer(_gs_ramp* ramp, T* dest, const T* src, size_t* bytes)
for (size_t sample = 0; sample < samples; sample++) {
float gain = *ramp->value;
dest[sample] = T(float(src[sample] - middle) * gain + middle);
dest[sample] = clamp<T, min, max>(float(src[sample] - middle) * gain
+ middle);
if (ChangeRamp(ramp)) {
*bytes = sample * sizeof(T);
@ -206,26 +207,26 @@ BFileGameSound::FillBuffer(void* inBuffer, size_t inByteCount)
switch(Format().format) {
case gs_audio_format::B_GS_U8:
rampDone = ::FillBuffer<uint8, 128>(fPausing,
(uint8*)&buffer[out_offset],
rampDone = ::FillBuffer<uint8, 0, 128, UINT8_MAX>(
fPausing, (uint8*)&buffer[out_offset],
(uint8*)&fBuffer[fPlayPosition], &bytes);
break;
case gs_audio_format::B_GS_S16:
rampDone = ::FillBuffer<int16, 0>(fPausing,
(int16*)&buffer[out_offset],
rampDone = ::FillBuffer<int16, INT16_MIN, 0, INT16_MAX>(
fPausing, (int16*)&buffer[out_offset],
(int16*)&fBuffer[fPlayPosition], &bytes);
break;
case gs_audio_format::B_GS_S32:
rampDone = ::FillBuffer<int32, 0>(fPausing,
(int32*)&buffer[out_offset],
rampDone = ::FillBuffer<int32, INT32_MIN, 0, INT32_MAX>(
fPausing, (int32*)&buffer[out_offset],
(int32*)&fBuffer[fPlayPosition], &bytes);
break;
case gs_audio_format::B_GS_F:
rampDone = ::FillBuffer<float, 0>(fPausing,
(float*)&buffer[out_offset],
rampDone = ::FillBuffer<float, -1, 0, 1>(
fPausing, (float*)&buffer[out_offset],
(float*)&fBuffer[fPlayPosition], &bytes);
break;
}

View File

@ -54,4 +54,13 @@ void media_to_gs_format(gs_audio_format* dest,
media_raw_audio_format* source);
template<typename T, int32 min, int32 max>
static inline T clamp(float value)
{
if (value <= min)
return min;
if (value >= max)
return max;
return T(value);
}
#endif

View File

@ -43,13 +43,14 @@
#include "GSUtility.h"
// Sound Buffer Utility functions ----------------------------------------
template<typename T, int middle>
template<typename T, int32 min, int32 middle, int32 max>
static inline void
ApplyMod(T* data, int64 index, float* pan)
{
data[index * 2] = T(float(data[index * 2] - middle) * pan[0] + middle);
data[index * 2 + 1] = T(float(data[index * 2 + 1] - middle) * pan[1]
+ middle);
data[index * 2] = clamp<T, min, max>(float(data[index * 2] - middle)
* pan[0] + middle);
data[index * 2 + 1] = clamp<T, min, max>(float(data[index * 2 + 1] - middle)
* pan[1] + middle);
}
@ -262,7 +263,7 @@ GameSoundBuffer::Play(void * data, int64 frames)
case gs_audio_format::B_GS_U8:
{
for (int64 i = 0; i < frames; i++) {
ApplyMod<uint8, 128>((uint8*)data, i, pan);
ApplyMod<uint8, 0, 128, UINT8_MAX>((uint8*)data, i, pan);
UpdateMods();
}
@ -272,7 +273,8 @@ GameSoundBuffer::Play(void * data, int64 frames)
case gs_audio_format::B_GS_S16:
{
for (int64 i = 0; i < frames; i++) {
ApplyMod<int16, 0>((int16*)data, i, pan);
ApplyMod<int16, INT16_MIN, 0, INT16_MAX>((int16*)data, i,
pan);
UpdateMods();
}
@ -282,7 +284,8 @@ GameSoundBuffer::Play(void * data, int64 frames)
case gs_audio_format::B_GS_S32:
{
for (int64 i = 0; i < frames; i++) {
ApplyMod<int32, 0>((int32*)data, i, pan);
ApplyMod<int32, INT32_MIN, 0, INT32_MAX>((int32*)data, i,
pan);
UpdateMods();
}
@ -292,7 +295,7 @@ GameSoundBuffer::Play(void * data, int64 frames)
case gs_audio_format::B_GS_F:
{
for (int64 i = 0; i < frames; i++) {
ApplyMod<float, 0>((float*)data, i, pan);
ApplyMod<float, -1, 0, 1>((float*)data, i, pan);
UpdateMods();
}