From 2e68fbd20741c99d199045a0599e614ca9a2e07e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1ximo=20Casta=C3=B1eda?= Date: Fri, 11 Dec 2020 20:43:11 +0100 Subject: [PATCH] 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 --- .../media/media-add-ons/mixer/Interpolate.cpp | 20 +++++++++++------- .../media/media-add-ons/mixer/Resampler.cpp | 18 ++++++++++------ .../media-add-ons/multi_audio/Resampler.cpp | 11 ++++++++-- .../plugins/raw_decoder/AudioConversion.cpp | 4 ++-- src/kits/game/FileGameSound.cpp | 21 ++++++++++--------- src/kits/game/GSUtility.h | 9 ++++++++ src/kits/game/GameSoundBuffer.cpp | 19 ++++++++++------- 7 files changed, 67 insertions(+), 35 deletions(-) diff --git a/src/add-ons/media/media-add-ons/mixer/Interpolate.cpp b/src/add-ons/media/media-add-ons/mixer/Interpolate.cpp index 48ffd26b3e..36cda95ef9 100644 --- a/src/add-ons/media/media-add-ons/mixer/Interpolate.cpp +++ b/src/add-ons/media/media-add-ons/mixer/Interpolate.cpp @@ -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; diff --git a/src/add-ons/media/media-add-ons/mixer/Resampler.cpp b/src/add-ons/media/media-add-ons/mixer/Resampler.cpp index 58f43fc161..1268527e18 100644 --- a/src/add-ons/media/media-add-ons/mixer/Resampler.cpp +++ b/src/add-ons/media/media-add-ons/mixer/Resampler.cpp @@ -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; diff --git a/src/add-ons/media/media-add-ons/multi_audio/Resampler.cpp b/src/add-ons/media/media-add-ons/multi_audio/Resampler.cpp index 5ff5e77fb0..42b11fb640 100644 --- a/src/add-ons/media/media-add-ons/multi_audio/Resampler.cpp +++ b/src/add-ons/media/media-add-ons/multi_audio/Resampler.cpp @@ -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); diff --git a/src/add-ons/media/plugins/raw_decoder/AudioConversion.cpp b/src/add-ons/media/plugins/raw_decoder/AudioConversion.cpp index c95f33690f..8a619bbf12 100644 --- a/src/add-ons/media/plugins/raw_decoder/AudioConversion.cpp +++ b/src/add-ons/media/plugins/raw_decoder/AudioConversion.cpp @@ -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; diff --git a/src/kits/game/FileGameSound.cpp b/src/kits/game/FileGameSound.cpp index 7463864a9f..749f1c959f 100644 --- a/src/kits/game/FileGameSound.cpp +++ b/src/kits/game/FileGameSound.cpp @@ -32,7 +32,7 @@ struct _gs_media_tracker { // Local utility functions ----------------------------------------------- -template +template 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(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(fPausing, - (uint8*)&buffer[out_offset], + rampDone = ::FillBuffer( + fPausing, (uint8*)&buffer[out_offset], (uint8*)&fBuffer[fPlayPosition], &bytes); break; case gs_audio_format::B_GS_S16: - rampDone = ::FillBuffer(fPausing, - (int16*)&buffer[out_offset], + rampDone = ::FillBuffer( + fPausing, (int16*)&buffer[out_offset], (int16*)&fBuffer[fPlayPosition], &bytes); break; case gs_audio_format::B_GS_S32: - rampDone = ::FillBuffer(fPausing, - (int32*)&buffer[out_offset], + rampDone = ::FillBuffer( + fPausing, (int32*)&buffer[out_offset], (int32*)&fBuffer[fPlayPosition], &bytes); break; case gs_audio_format::B_GS_F: - rampDone = ::FillBuffer(fPausing, - (float*)&buffer[out_offset], + rampDone = ::FillBuffer( + fPausing, (float*)&buffer[out_offset], (float*)&fBuffer[fPlayPosition], &bytes); break; } diff --git a/src/kits/game/GSUtility.h b/src/kits/game/GSUtility.h index 1e886c1d00..6759be6913 100644 --- a/src/kits/game/GSUtility.h +++ b/src/kits/game/GSUtility.h @@ -54,4 +54,13 @@ void media_to_gs_format(gs_audio_format* dest, media_raw_audio_format* source); +template +static inline T clamp(float value) +{ + if (value <= min) + return min; + if (value >= max) + return max; + return T(value); +} #endif diff --git a/src/kits/game/GameSoundBuffer.cpp b/src/kits/game/GameSoundBuffer.cpp index 294803b0fb..1ac56a9b07 100644 --- a/src/kits/game/GameSoundBuffer.cpp +++ b/src/kits/game/GameSoundBuffer.cpp @@ -43,13 +43,14 @@ #include "GSUtility.h" // Sound Buffer Utility functions ---------------------------------------- -template +template 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(float(data[index * 2] - middle) + * pan[0] + middle); + data[index * 2 + 1] = clamp(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*)data, i, pan); + ApplyMod((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*)data, i, pan); + ApplyMod((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*)data, i, pan); + ApplyMod((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*)data, i, pan); + ApplyMod((float*)data, i, pan); UpdateMods(); }