winamp/Src/Plugins/Input/in_wmvdrm/GainLayer.cpp
2024-09-24 14:54:57 +02:00

233 lines
6.0 KiB
C++

#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();
}