Mercurial > audlegacy-plugins
comparison src/modplug/snd_eq.cxx @ 2216:3673c7ec4ea2
Sync with schism's modplug engine. Suggested by G¸«ärkan Seng¸«än.
author | William Pitcock <nenolod@atheme.org> |
---|---|
date | Fri, 07 Dec 2007 12:08:47 -0600 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
2198:32f9f1e4a9ec | 2216:3673c7ec4ea2 |
---|---|
1 /* | |
2 * This program is free software; you can redistribute it and modify it | |
3 * under the terms of the GNU General Public License as published by the | |
4 * Free Software Foundation; either version 2 of the license or (at your | |
5 * option) any later version. | |
6 * | |
7 * Authors: Olivier Lapicque <olivierl@jps.net> | |
8 * | |
9 * Name Date Description | |
10 * | |
11 * Olivier Lapicque --/--/-- Creation | |
12 * Trevor Nunes 26/01/04 conditional compilation for AMD,MMX calls | |
13 * | |
14 */ | |
15 #include "stdafx.h" | |
16 #include "sndfile.h" | |
17 #include <math.h> | |
18 | |
19 | |
20 #define EQ_BANDWIDTH 2.0 | |
21 #define EQ_ZERO 0.000001 | |
22 #define REAL float | |
23 | |
24 extern REAL MixFloatBuffer[]; | |
25 | |
26 extern void StereoMixToFloat(const int *pSrc, float *pOut1, float *pOut2, UINT nCount); | |
27 extern void FloatToStereoMix(const float *pIn1, const float *pIn2, int *pOut, UINT nCount); | |
28 extern void MonoMixToFloat(const int *pSrc, float *pOut, UINT nCount); | |
29 extern void FloatToMonoMix(const float *pIn, int *pOut, UINT nCount); | |
30 | |
31 typedef struct _EQBANDSTRUCT | |
32 { | |
33 REAL a0, a1, a2, b1, b2; | |
34 REAL x1, x2, y1, y2; | |
35 REAL Gain, CenterFrequency; | |
36 BOOL bEnable; | |
37 } EQBANDSTRUCT, *PEQBANDSTRUCT; | |
38 | |
39 UINT gEqLinearToDB[33] = | |
40 { | |
41 16, 19, 22, 25, 28, 31, 34, 37, | |
42 40, 43, 46, 49, 52, 55, 58, 61, | |
43 64, 76, 88, 100, 112, 124, 136, 148, | |
44 160, 172, 184, 196, 208, 220, 232, 244, 256 | |
45 }; | |
46 | |
47 | |
48 //static REAL f2ic = (REAL)(1 << 28); | |
49 //static REAL i2fc = (REAL)(1.0 / (1 << 28)); | |
50 | |
51 static EQBANDSTRUCT gEQ[MAX_EQ_BANDS*2] = | |
52 { | |
53 // Default: Flat EQ | |
54 {0,0,0,0,0, 0,0,0,0, 1, 120, FALSE}, | |
55 {0,0,0,0,0, 0,0,0,0, 1, 600, FALSE}, | |
56 {0,0,0,0,0, 0,0,0,0, 1, 1200, FALSE}, | |
57 {0,0,0,0,0, 0,0,0,0, 1, 3000, FALSE}, | |
58 {0,0,0,0,0, 0,0,0,0, 1, 6000, FALSE}, | |
59 {0,0,0,0,0, 0,0,0,0, 1, 10000, FALSE}, | |
60 {0,0,0,0,0, 0,0,0,0, 1, 120, FALSE}, | |
61 {0,0,0,0,0, 0,0,0,0, 1, 600, FALSE}, | |
62 {0,0,0,0,0, 0,0,0,0, 1, 1200, FALSE}, | |
63 {0,0,0,0,0, 0,0,0,0, 1, 3000, FALSE}, | |
64 {0,0,0,0,0, 0,0,0,0, 1, 6000, FALSE}, | |
65 {0,0,0,0,0, 0,0,0,0, 1, 10000, FALSE}, | |
66 }; | |
67 | |
68 void EQFilter(EQBANDSTRUCT *pbs, REAL *pbuffer, UINT nCount) | |
69 //---------------------------------------------------------- | |
70 { | |
71 for (UINT i=0; i<nCount; i++) | |
72 { | |
73 REAL x = pbuffer[i]; | |
74 REAL y = pbs->a1 * pbs->x1 + pbs->a2 * pbs->x2 + pbs->a0 * x + pbs->b1 * pbs->y1 + pbs->b2 * pbs->y2; | |
75 pbs->x2 = pbs->x1; | |
76 pbs->y2 = pbs->y1; | |
77 pbs->x1 = x; | |
78 pbuffer[i] = y; | |
79 pbs->y1 = y; | |
80 } | |
81 } | |
82 | |
83 void CSoundFile::EQMono(int *pbuffer, UINT nCount) | |
84 //------------------------------------------------ | |
85 { | |
86 MonoMixToFloat(pbuffer, MixFloatBuffer, nCount); | |
87 for (UINT b=0; b<MAX_EQ_BANDS; b++) | |
88 { | |
89 if ((gEQ[b].bEnable) && (gEQ[b].Gain != 1.0f)) | |
90 EQFilter(&gEQ[b], MixFloatBuffer, nCount); | |
91 } | |
92 FloatToMonoMix(MixFloatBuffer, pbuffer, nCount); | |
93 } | |
94 | |
95 void CSoundFile::EQStereo(int *pbuffer, UINT nCount) | |
96 //-------------------------------------------------- | |
97 { | |
98 StereoMixToFloat(pbuffer, MixFloatBuffer, MixFloatBuffer+MIXBUFFERSIZE, nCount); | |
99 | |
100 for (UINT bl=0; bl<MAX_EQ_BANDS; bl++) | |
101 { | |
102 if ((gEQ[bl].bEnable) && (gEQ[bl].Gain != 1.0f)) | |
103 EQFilter(&gEQ[bl], MixFloatBuffer, nCount); | |
104 } | |
105 for (UINT br=MAX_EQ_BANDS; br<MAX_EQ_BANDS*2; br++) | |
106 { | |
107 if ((gEQ[br].bEnable) && (gEQ[br].Gain != 1.0f)) | |
108 EQFilter(&gEQ[br], MixFloatBuffer+MIXBUFFERSIZE, nCount); | |
109 } | |
110 | |
111 FloatToStereoMix(MixFloatBuffer, MixFloatBuffer+MIXBUFFERSIZE, pbuffer, nCount); | |
112 | |
113 } | |
114 | |
115 void CSoundFile::InitializeEQ(BOOL bReset) | |
116 //---------------------------------------- | |
117 { | |
118 REAL fMixingFreq = (REAL)gdwMixingFreq; | |
119 // Gain = 0.5 (-6dB) .. 2 (+6dB) | |
120 for (UINT band=0; band<MAX_EQ_BANDS*2; band++) if (gEQ[band].bEnable) | |
121 { | |
122 REAL k, k2, r, f; | |
123 REAL v0, v1; | |
124 BOOL b = bReset; | |
125 | |
126 f = gEQ[band].CenterFrequency / fMixingFreq; | |
127 if (f > 0.45f) gEQ[band].Gain = 1; | |
128 // if (f > 0.25) f = 0.25; | |
129 // k = tan(PI*f); | |
130 k = f * 3.141592654f; | |
131 k = k + k*f; | |
132 // if (k > (REAL)0.707) k = (REAL)0.707; | |
133 k2 = k*k; | |
134 v0 = gEQ[band].Gain; | |
135 v1 = 1; | |
136 if (gEQ[band].Gain < 1.0) | |
137 { | |
138 v0 *= (0.5f/EQ_BANDWIDTH); | |
139 v1 *= (0.5f/EQ_BANDWIDTH); | |
140 } else | |
141 { | |
142 v0 *= (1.0f/EQ_BANDWIDTH); | |
143 v1 *= (1.0f/EQ_BANDWIDTH); | |
144 } | |
145 r = (1 + v0*k + k2) / (1 + v1*k + k2); | |
146 if (r != gEQ[band].a0) | |
147 { | |
148 gEQ[band].a0 = r; | |
149 b = TRUE; | |
150 } | |
151 r = 2 * (k2 - 1) / (1 + v1*k + k2); | |
152 if (r != gEQ[band].a1) | |
153 { | |
154 gEQ[band].a1 = r; | |
155 b = TRUE; | |
156 } | |
157 r = (1 - v0*k + k2) / (1 + v1*k + k2); | |
158 if (r != gEQ[band].a2) | |
159 { | |
160 gEQ[band].a2 = r; | |
161 b = TRUE; | |
162 } | |
163 r = - 2 * (k2 - 1) / (1 + v1*k + k2); | |
164 if (r != gEQ[band].b1) | |
165 { | |
166 gEQ[band].b1 = r; | |
167 b = TRUE; | |
168 } | |
169 r = - (1 - v1*k + k2) / (1 + v1*k + k2); | |
170 if (r != gEQ[band].b2) | |
171 { | |
172 gEQ[band].b2 = r; | |
173 b = TRUE; | |
174 } | |
175 if (b) | |
176 { | |
177 gEQ[band].x1 = 0; | |
178 gEQ[band].x2 = 0; | |
179 gEQ[band].y1 = 0; | |
180 gEQ[band].y2 = 0; | |
181 } | |
182 } else | |
183 { | |
184 gEQ[band].a0 = 0; | |
185 gEQ[band].a1 = 0; | |
186 gEQ[band].a2 = 0; | |
187 gEQ[band].b1 = 0; | |
188 gEQ[band].b2 = 0; | |
189 gEQ[band].x1 = 0; | |
190 gEQ[band].x2 = 0; | |
191 gEQ[band].y1 = 0; | |
192 gEQ[band].y2 = 0; | |
193 } | |
194 } | |
195 | |
196 | |
197 void CSoundFile::SetEQGains(const UINT *pGains, UINT nGains, const UINT *pFreqs, BOOL bReset) | |
198 //------------------------------------------------------------------------------------------- | |
199 { | |
200 for (UINT i=0; i<MAX_EQ_BANDS; i++) | |
201 { | |
202 REAL g, f = 0; | |
203 if (i < nGains) | |
204 { | |
205 UINT n = pGains[i]; | |
206 // if (n > 32) n = 32; | |
207 g = 1.0 + (((double)n) / 64.0); | |
208 if (pFreqs) f = (REAL)(int)pFreqs[i]; | |
209 } else | |
210 { | |
211 g = 1; | |
212 } | |
213 gEQ[i].Gain = g; | |
214 gEQ[i].CenterFrequency = f; | |
215 gEQ[i+MAX_EQ_BANDS].Gain = g; | |
216 gEQ[i+MAX_EQ_BANDS].CenterFrequency = f; | |
217 if (f > 20.0f && i < nGains) /* don't enable bands outside... */ | |
218 { | |
219 gEQ[i].bEnable = TRUE; | |
220 gEQ[i+MAX_EQ_BANDS].bEnable = TRUE; | |
221 } else | |
222 { | |
223 gEQ[i].bEnable = FALSE; | |
224 gEQ[i+MAX_EQ_BANDS].bEnable = FALSE; | |
225 } | |
226 } | |
227 InitializeEQ(bReset); | |
228 } |