aboutsummaryrefslogtreecommitdiff
path: root/Src/Plugins/Input/in_wmvdrm/GainLayer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Src/Plugins/Input/in_wmvdrm/GainLayer.cpp')
-rw-r--r--Src/Plugins/Input/in_wmvdrm/GainLayer.cpp232
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();
+}