diff options
Diffstat (limited to 'Src/Plugins/Input/in_wmvdrm/GainLayer.cpp')
-rw-r--r-- | Src/Plugins/Input/in_wmvdrm/GainLayer.cpp | 232 |
1 files changed, 232 insertions, 0 deletions
diff --git a/Src/Plugins/Input/in_wmvdrm/GainLayer.cpp b/Src/Plugins/Input/in_wmvdrm/GainLayer.cpp new file mode 100644 index 00000000..84811f79 --- /dev/null +++ b/Src/Plugins/Input/in_wmvdrm/GainLayer.cpp @@ -0,0 +1,232 @@ +#include "main.h" +#include "GainLayer.h" +#include <malloc.h> +#include <math.h> +#include <locale.h> +#include "api.h" + +static void FillFloat(float *floatBuf, void *samples, size_t bps, size_t numSamples, size_t numChannels, float preamp) +{ + switch (bps) + { + case 8: + { + unsigned __int8 *samples8 = (unsigned __int8 *)samples; + size_t totalSamples = numSamples * numChannels; + for (size_t x = 0; x != totalSamples; x ++) + { + floatBuf[x] = (float)(samples8[x] - 128) * preamp; + } + } + break; + case 16: + { + short *samples16 = (short *)samples; + size_t totalSamples = numSamples * numChannels; + for (size_t x = 0; x != totalSamples; x ++) + { + floatBuf[x] = (float)samples16[x] * preamp; + } + } + break; + case 24: + { + unsigned __int8 *samples8 = (unsigned __int8 *)samples; + size_t totalSamples = numSamples * numChannels; + for (size_t x = 0; x != totalSamples; x ++) + { + long temp = (((long)samples8[0]) << 8); + temp = temp | (((long)samples8[1]) << 16); + temp = temp | (((long)samples8[2]) << 24); + floatBuf[x] = (float)temp * preamp; + samples8 += 3; + } + } + break; + } +} + +inline static float fastclip(float x, const float a, const float b) +{ + float x1 = (float)fabs (x - a); + float x2 = (float)fabs (x - b); + x = x1 + (a + b); + x -= x2; + x *= 0.5f; + return (x); +} + +#define PA_CLIP_( val, min, max )\ + { val = ((val) < (min)) ? (min) : (((val) > (max)) ? (max) : (val)); } + +void Float32_To_Int16_Clip( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count) +{ + float *src = (float*)sourceBuffer; + signed short *dest = (signed short*)destinationBuffer; + + while ( count-- ) + { + long samp = lrint(*src); + + PA_CLIP_( samp, -0x8000, 0x7FFF ); + *dest = (signed short) samp; + + src += sourceStride; + dest += destinationStride; + } +} +inline static void clip(double &x, double a, double b) +{ + double x1 = fabs (x - a); + double x2 = fabs (x - b); + x = x1 + (a + b); + x -= x2; + x *= 0.5; +} + +void Float32_To_Int24_Clip( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count) +{ + float *src = (float*)sourceBuffer; + unsigned char *dest = (unsigned char*)destinationBuffer; + + while ( count-- ) + { + /* convert to 32 bit and drop the low 8 bits */ + double scaled = *src; + clip( scaled, -2147483648., 2147483647. ); + signed long temp = (signed long) scaled; + + dest[0] = (unsigned char)(temp >> 8); + dest[1] = (unsigned char)(temp >> 16); + dest[2] = (unsigned char)(temp >> 24); + src += sourceStride; + dest += destinationStride * 3; + } +} + +static void FillSamples(void *samples, float *floatBuf, size_t bps, size_t numSamples, size_t numChannels) +{ + switch (bps) + { + case 16: + Float32_To_Int16_Clip(samples, 1, floatBuf, 1, numSamples*numChannels); + break; + case 24: + Float32_To_Int24_Clip(samples, 1, floatBuf, 1, numSamples*numChannels); + break; + + } +} + +float GetGain(WMInformation *info, bool allowDefault) +{ + if (AGAVE_API_CONFIG && AGAVE_API_CONFIG->GetBool(playbackConfigGroupGUID, L"replaygain", false)) + { + float dB = 0, peak = 1.0f; + wchar_t gain[64]=L"", peakVal[64]=L""; + switch (AGAVE_API_CONFIG->GetUnsigned(playbackConfigGroupGUID, L"replaygain_source", 0)) + { + case 0: // track + info->GetAttribute(L"replaygain_track_gain", gain, 64); + if (!gain[0] && !AGAVE_API_CONFIG->GetBool(playbackConfigGroupGUID, L"replaygain_preferred_only", false)) + info->GetAttribute(L"replaygain_album_gain", gain, 64); + + info->GetAttribute(L"replaygain_track_peak", peakVal, 64); + if (!peakVal[0] && !AGAVE_API_CONFIG->GetBool(playbackConfigGroupGUID, L"replaygain_preferred_only", false)) + info->GetAttribute(L"replaygain_album_peak", peakVal, 64); + + break; + case 1: + info->GetAttribute(L"replaygain_album_gain", gain, 64); + if (!gain[0] && !AGAVE_API_CONFIG->GetBool(playbackConfigGroupGUID, L"replaygain_preferred_only", false)) + info->GetAttribute(L"replaygain_track_gain", gain, 64); + + info->GetAttribute(L"replaygain_album_peak", peakVal, 64); + if (!peakVal[0] && !AGAVE_API_CONFIG->GetBool(playbackConfigGroupGUID, L"replaygain_preferred_only", false)) + info->GetAttribute(L"replaygain_track_peak", peakVal, 64); + + break; + } + + _locale_t C_locale = WASABI_API_LNG->Get_C_NumericLocale(); + + if (gain[0]) + { + if (gain[0] == L'+') + dB = static_cast<float>(_wtof_l(&gain[1],C_locale)); + else + dB = static_cast<float>(_wtof_l(gain,C_locale)); + } + else if (allowDefault) + { + dB = AGAVE_API_CONFIG->GetFloat(playbackConfigGroupGUID, L"non_replaygain", -6.0); + return powf(10.0f, dB / 20.0f); + } + + if (peakVal[0]) + { + peak = static_cast<float>(_wtof_l(peakVal,C_locale)); + } + + switch (AGAVE_API_CONFIG->GetUnsigned(playbackConfigGroupGUID, L"replaygain_mode", 1)) + { + case 0: // apply gain + return powf(10.0f, dB / 20.0f); + case 1: // apply gain, but don't clip + return min(powf(10.0f, dB / 20.0f), 1.0f / peak); + case 2: // normalize + return 1.0f / peak; + case 3: // prevent clipping + if (peak > 1.0f) + return 1.0f / peak; + else + return 1.0f; + } + + } + + return 1.0f; // no gain +} + + +void GainLayer::AudioDataReceived(void *_data, unsigned long sizeBytes, DWORD timestamp) +{ + if (enabled) + { + size_t samples = audio->AudioBytesToSamples(sizeBytes); + int channels = audio->Channels(); + if (floatSize < (samples * channels)) + { + delete [] floatData; + floatSize = samples * channels; + floatData = new float[floatSize]; + } + if (outSize < sizeBytes) + { + delete [] outData; + outSize=sizeBytes; + outData = (void *)new __int8[sizeBytes]; + } + + FillFloat(floatData, _data, audio->BitSize(), samples , channels, replayGain); + FillSamples(outData, floatData, audio->BitSize(), samples , channels); + + WMHandler::AudioDataReceived(outData, sizeBytes, timestamp); + } + else + WMHandler::AudioDataReceived(_data, sizeBytes, timestamp); +} + +void GainLayer::Opened() +{ + enabled= (AGAVE_API_CONFIG && AGAVE_API_CONFIG->GetBool(playbackConfigGroupGUID, L"replaygain", false)); + if (enabled) + replayGain = GetGain(info, true); + WMHandler::Opened(); +} |