view src/modplug/snd_eq.cxx @ 2284:d19b53359b24

cleaned up the sndfile wav plugin, currently limiting it ONLY TO WAV PLAYBACK. if somebody is more experienced with it and wants to restore the other formats, go ahead (maybe change the name of the plugin too?).
author mf0102 <0102@gmx.at>
date Wed, 09 Jan 2008 15:41:22 +0100
parents 3673c7ec4ea2
children
line wrap: on
line source

/*
 * This program is  free software; you can redistribute it  and modify it
 * under the terms of the GNU  General Public License as published by the
 * Free Software Foundation; either version 2  of the license or (at your
 * option) any later version.
 *
 * Authors: Olivier Lapicque <olivierl@jps.net>
 *
 * Name                Date             Description
 * 
 * Olivier Lapicque    --/--/--         Creation
 * Trevor Nunes        26/01/04         conditional compilation for AMD,MMX calls
 *
*/
#include "stdafx.h"
#include "sndfile.h"
#include <math.h>


#define EQ_BANDWIDTH	2.0
#define EQ_ZERO			0.000001
#define REAL			float

extern REAL MixFloatBuffer[];

extern void StereoMixToFloat(const int *pSrc, float *pOut1, float *pOut2, UINT nCount);
extern void FloatToStereoMix(const float *pIn1, const float *pIn2, int *pOut, UINT nCount);
extern void MonoMixToFloat(const int *pSrc, float *pOut, UINT nCount);
extern void FloatToMonoMix(const float *pIn, int *pOut, UINT nCount);

typedef struct _EQBANDSTRUCT
{
	REAL a0, a1, a2, b1, b2;
	REAL x1, x2, y1, y2;
	REAL Gain, CenterFrequency;
	BOOL bEnable;
} EQBANDSTRUCT, *PEQBANDSTRUCT;

UINT gEqLinearToDB[33] =
{
	16, 19, 22, 25, 28, 31, 34, 37,
	40, 43, 46, 49, 52, 55, 58, 61,
	64, 76, 88, 100, 112, 124, 136, 148,
	160, 172, 184, 196, 208, 220, 232, 244, 256
};


//static REAL f2ic = (REAL)(1 << 28);
//static REAL i2fc = (REAL)(1.0 / (1 << 28));

static EQBANDSTRUCT gEQ[MAX_EQ_BANDS*2] =
{
	// Default: Flat EQ
	{0,0,0,0,0, 0,0,0,0, 1,   120, FALSE},
	{0,0,0,0,0, 0,0,0,0, 1,   600, FALSE},
	{0,0,0,0,0, 0,0,0,0, 1,  1200, FALSE},
	{0,0,0,0,0, 0,0,0,0, 1,  3000, FALSE},
	{0,0,0,0,0, 0,0,0,0, 1,  6000, FALSE},
	{0,0,0,0,0, 0,0,0,0, 1, 10000, FALSE},
	{0,0,0,0,0, 0,0,0,0, 1,   120, FALSE},
	{0,0,0,0,0, 0,0,0,0, 1,   600, FALSE},
	{0,0,0,0,0, 0,0,0,0, 1,  1200, FALSE},
	{0,0,0,0,0, 0,0,0,0, 1,  3000, FALSE},
	{0,0,0,0,0, 0,0,0,0, 1,  6000, FALSE},
	{0,0,0,0,0, 0,0,0,0, 1, 10000, FALSE},
};

void EQFilter(EQBANDSTRUCT *pbs, REAL *pbuffer, UINT nCount)
//----------------------------------------------------------
{
	for (UINT i=0; i<nCount; i++)
	{
		REAL x = pbuffer[i];
		REAL y = pbs->a1 * pbs->x1 + pbs->a2 * pbs->x2 + pbs->a0 * x + pbs->b1 * pbs->y1 + pbs->b2 * pbs->y2;
		pbs->x2 = pbs->x1;
		pbs->y2 = pbs->y1;
		pbs->x1 = x;
		pbuffer[i] = y;
		pbs->y1 = y;
	}
}

void CSoundFile::EQMono(int *pbuffer, UINT nCount)
//------------------------------------------------
{
	MonoMixToFloat(pbuffer, MixFloatBuffer, nCount);
	for (UINT b=0; b<MAX_EQ_BANDS; b++)
	{
		if ((gEQ[b].bEnable) && (gEQ[b].Gain != 1.0f))
			EQFilter(&gEQ[b], MixFloatBuffer, nCount);
	}
	FloatToMonoMix(MixFloatBuffer, pbuffer, nCount);
}

void CSoundFile::EQStereo(int *pbuffer, UINT nCount)
//--------------------------------------------------
{
	StereoMixToFloat(pbuffer, MixFloatBuffer, MixFloatBuffer+MIXBUFFERSIZE, nCount);
		
	for (UINT bl=0; bl<MAX_EQ_BANDS; bl++)
	{
		if ((gEQ[bl].bEnable) && (gEQ[bl].Gain != 1.0f))
			EQFilter(&gEQ[bl], MixFloatBuffer, nCount);
	}
	for (UINT br=MAX_EQ_BANDS; br<MAX_EQ_BANDS*2; br++)
	{
		if ((gEQ[br].bEnable) && (gEQ[br].Gain != 1.0f))
			EQFilter(&gEQ[br], MixFloatBuffer+MIXBUFFERSIZE, nCount);
	}

	FloatToStereoMix(MixFloatBuffer, MixFloatBuffer+MIXBUFFERSIZE, pbuffer, nCount);

}

void CSoundFile::InitializeEQ(BOOL bReset)
//----------------------------------------
{
	REAL fMixingFreq = (REAL)gdwMixingFreq;
	// Gain = 0.5 (-6dB) .. 2 (+6dB)
	for (UINT band=0; band<MAX_EQ_BANDS*2; band++) if (gEQ[band].bEnable)
	{
		REAL k, k2, r, f;
		REAL v0, v1;
		BOOL b = bReset;

		f = gEQ[band].CenterFrequency / fMixingFreq;
		if (f > 0.45f) gEQ[band].Gain = 1;
		// if (f > 0.25) f = 0.25;
		// k = tan(PI*f);
		k = f * 3.141592654f;
		k = k + k*f;
//		if (k > (REAL)0.707) k = (REAL)0.707;
		k2 = k*k;
		v0 = gEQ[band].Gain;
		v1 = 1;
		if (gEQ[band].Gain < 1.0)
		{
			v0 *= (0.5f/EQ_BANDWIDTH);
			v1 *= (0.5f/EQ_BANDWIDTH);
		} else
		{
			v0 *= (1.0f/EQ_BANDWIDTH);
			v1 *= (1.0f/EQ_BANDWIDTH);
		}
		r = (1 + v0*k + k2) / (1 + v1*k + k2);
		if (r != gEQ[band].a0)
		{
			gEQ[band].a0 = r;
			b = TRUE;
		}
		r = 2 * (k2 - 1) / (1 + v1*k + k2);
		if (r != gEQ[band].a1)
		{
			gEQ[band].a1 = r;
			b = TRUE;
		}
		r = (1 - v0*k + k2) / (1 + v1*k + k2);
		if (r != gEQ[band].a2)
		{
			gEQ[band].a2 = r;
			b = TRUE;
		}
		r = - 2 * (k2 - 1) / (1 + v1*k + k2);
		if (r != gEQ[band].b1)
		{
			gEQ[band].b1 = r;
			b = TRUE;
		}
		r = - (1 - v1*k + k2) / (1 + v1*k + k2);
		if (r != gEQ[band].b2)
		{
			gEQ[band].b2 = r;
			b = TRUE;
		}
		if (b)
		{
			gEQ[band].x1 = 0;
			gEQ[band].x2 = 0;
			gEQ[band].y1 = 0;
			gEQ[band].y2 = 0;
		}
	} else
	{
		gEQ[band].a0 = 0;
		gEQ[band].a1 = 0;
		gEQ[band].a2 = 0;
		gEQ[band].b1 = 0;
		gEQ[band].b2 = 0;
		gEQ[band].x1 = 0;
		gEQ[band].x2 = 0;
		gEQ[band].y1 = 0;
		gEQ[band].y2 = 0;
	}
}


void CSoundFile::SetEQGains(const UINT *pGains, UINT nGains, const UINT *pFreqs, BOOL bReset)
//-------------------------------------------------------------------------------------------
{
	for (UINT i=0; i<MAX_EQ_BANDS; i++)
	{
		REAL g, f = 0;
		if (i < nGains)
		{
			UINT n = pGains[i];
//			if (n > 32) n = 32;
			g = 1.0 + (((double)n) / 64.0);
			if (pFreqs) f = (REAL)(int)pFreqs[i];
		} else
		{
			g = 1;
		}
		gEQ[i].Gain = g;
		gEQ[i].CenterFrequency = f;
		gEQ[i+MAX_EQ_BANDS].Gain = g;
		gEQ[i+MAX_EQ_BANDS].CenterFrequency = f;
		if (f > 20.0f && i < nGains) /* don't enable bands outside... */
		{
			gEQ[i].bEnable = TRUE;
			gEQ[i+MAX_EQ_BANDS].bEnable = TRUE;
		} else
		{
			gEQ[i].bEnable = FALSE;
			gEQ[i+MAX_EQ_BANDS].bEnable = FALSE;
		}
	}
	InitializeEQ(bReset);
}